/* $Id:   Broadcom SDK $
 * $Copyright: Copyright 2011 Broadcom Corporation.
 * This program is the proprietary software of Broadcom Corporation
 * and/or its licensors, and may only be used, duplicated, modified
 * or distributed pursuant to the terms and conditions of a separate,
 * written license agreement executed between you and Broadcom
 * (an "Authorized License").  Except as set forth in an Authorized
 * License, Broadcom grants no license (express or implied), right
 * to use, or waiver of any kind with respect to the Software, and
 * Broadcom expressly reserves all rights in and to the Software
 * and all intellectual property rights therein.  IF YOU HAVE
 * NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS SOFTWARE
 * IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
 * ALL USE OF THE SOFTWARE.  
 *  
 * Except as expressly set forth in the Authorized License,
 *  
 * 1.     This program, including its structure, sequence and organization,
 * constitutes the valuable trade secrets of Broadcom, and you shall use
 * all reasonable efforts to protect the confidentiality thereof,
 * and to use this information only in connection with your use of
 * Broadcom integrated circuit products.
 *  
 * 2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS
 * PROVIDED "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
 * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
 * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE.  BROADCOM SPECIFICALLY
 * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
 * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
 * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
 * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING
 * OUT OF USE OR PERFORMANCE OF THE SOFTWARE.
 * 
 * 3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL
 * BROADCOM OR ITS LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL,
 * INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY DAMAGES WHATSOEVER
 * ARISING OUT OF OR IN ANY WAY RELATING TO YOUR USE OF OR INABILITY
 * TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF
 * THE AMOUNT ACTUALLY PAID FOR THE SOFTWARE ITSELF OR USD 1.00,
 * WHICHEVER IS GREATER. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING
 * ANY FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.$
 *
 * Module: Field Processor APIs
 *
 * Purpose:
 *     API for Field Processor (FP) for XGS3 family and later.
 *
 *
 */
#include <soc/mem.h>
#include <soc/debug.h>
#include <soc/drv.h>
#include <soc/cmic.h>
#include <soc/field.h>

#include <shared/pbmp.h>

#include <bcm/field.h>
#include <bcm/error.h>
#include <bcm/mirror.h>

#if defined(BCM_EASYRIDER_SUPPORT)
#include <bcm_int/esw/easyrider.h>
#endif /* BCM_EASYRIDER_SUPPORT */
#include <bcm_int/esw/field.h>
#include <bcm_int/esw/firebolt.h>
#include <bcm_int/esw/raptor.h>
#include <bcm_int/esw/trx.h>
#include <bcm_int/esw/triumph.h>
#include <bcm_int/esw/triumph2.h>
#include <bcm_int/esw/trident.h>
#include <bcm_int/esw/katana.h>
#include <bcm_int/common/multicast.h>
#include <bcm_int/esw/enduro.h>
#include <bcm_int/esw/hurricane.h>
#include <bcm_int/esw/scorpion.h>
#include <bcm_int/esw/trunk.h>
#include <bcm_int/esw/mirror.h>
#include <bcm_int/esw/stack.h>
#include <bcm_int/esw/port.h>
#include <bcm_int/control.h>

#include <bcm_int/esw_dispatch.h>
#include <bcm_int/esw/flex_ctr.h>
#if defined(BCM_KATANA_SUPPORT)
#include <bcm_int/esw/policer.h>
#endif

#ifdef BCM_FIELD_SUPPORT 
/* Static variables */
static uint32 last_allocated_eid;
int prio_set_with_no_free_entries = FALSE; 

/*
 * Macro:
 *     FIELD_IS_INIT (internal)
 * Purpose:
 *     Check that the unit is valid and confirm that the field functions
 *     are initialized.
 * Parameters:
 *     unit - BCM device number
 * Notes:
 *     Results in return(BCM_E_UNIT), return(BCM_E_UNAVAIL), or
 *     return(BCM_E_INIT) if fails.
 */
#define FIELD_IS_INIT(unit)                                      \
    if (!soc_feature(unit, soc_feature_field)) {                 \
        return (BCM_E_UNAVAIL);                                  \
    }                                                            \
    if (_field_control[unit] == NULL) {                          \
        FP_ERR(("FP(unit %d) Error: not initialized\n", unit));   \
        return (BCM_E_INIT);                                     \
    }

/*
 *STATIC  Macro:
 *     FP_LOCK
 * Purpose:
 *     Lock take the Field control mutex
 */
#define FP_LOCK(control) \
    sal_mutex_take((control)->fc_lock, sal_mutex_FOREVER)

/*
 * Macro:
 *     FP_UNLOCK
 * Purpose:
 *     Lock take the Field control mutex
 */
#define FP_UNLOCK(control) \
    sal_mutex_give((control)->fc_lock);

/*
 * Local function prototypes
 */
#ifdef BROADCOM_DEBUG
STATIC char *_field_qual_name(bcm_field_qualify_t qid);
STATIC char *_field_qual_stage_name(bcm_field_stage_t stage);
STATIC char *_field_qual_IpType_name(bcm_field_IpType_t type);
STATIC char *_field_action_name(bcm_field_action_t action);
STATIC char *_field_group_mode_name(uint32 group_flags);
#endif /* BROADCOM_DEBUG */

STATIC int _field_entry_move(int unit, _field_entry_t *f_ent, int tcam_idx_new);
STATIC int _field_group_add(int unit, _field_group_add_fsm_t *fsm_ptr);
STATIC int _field_stat_destroy_all(int unit);

int _field_stat_value_get(int unit, _field_stat_t *f_st,
        bcm_field_stat_t stat, uint64 *value);

int _field_stat_value_set(int unit, _field_stat_t *f_st,
        bcm_field_stat_t stat, uint64 value);
/*
 * Field control data, one per device.
 */
static _field_control_t         *_field_control[BCM_MAX_NUM_UNITS];

/* Accessor to last_allocated_eid from other files */
#ifdef BCM_WARM_BOOT_SUPPORT

#define BCM_WB_VERSION_1_1                SOC_SCACHE_VERSION(1,1)
#define BCM_WB_VERSION_1_0                SOC_SCACHE_VERSION(1,0)
#define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_1


#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)

/* Extract a field from a raw HW entry */

void
_field_extract(uint32 *buf, int offset, int width, uint32 *value)
{
    int idx, wp, bp, len;
    wp = offset / 32;
    bp = offset & (32 - 1);
    idx = 0;

    for (len = width; len > 0; len -= 32) {
        if (bp) {
            value[idx] = (buf[wp++] >> bp) & ((1 << (32 - bp)) - 1);
            value[idx] |= buf[wp] << (32 - bp);
        } else {
            value[idx] = buf[wp];
        }

        if (len < 32) {
            value[idx] &= ((1 << len) - 1);
        }

        idx++;
    }

    return;
}

#endif

STATIC int
_field_state_cleanup(int unit, _field_control_t *fc)
{
    int rv;
    _field_group_t *fg;

    /* Destroy all entries in unit. */
    rv = bcm_esw_field_entry_destroy_all(unit);
    if (BCM_FAILURE(rv)) {
        return (rv);
    }

    /* Destroy all statistics entities. */
    FP_LOCK(fc);
    rv = _field_stat_destroy_all(unit);
    if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
        return (rv);
    }
    FP_UNLOCK(fc);

    /* Destroy all policers. */
    rv = bcm_esw_policer_destroy_all(unit);
    if (BCM_FAILURE(rv)) {
        return (rv);
    }

    /* Destroy all groups in unit. */
    fg = fc->groups;
    while (fg != NULL) {
        
        rv = bcm_esw_field_group_destroy(unit, fg->gid);
        if (BCM_FAILURE(rv)) {
            return (rv);
        }
        fg = fc->groups;
    }
    return rv;
}

void
_bcm_field_last_alloc_eid_incr(void)
{
    last_allocated_eid++;
    return;
}
int 
_bcm_field_last_alloc_eid_get(void)
{
    return last_allocated_eid;
}

/* Update the scache based on the latest field state */
int
_bcm_esw_field_scache_sync(int unit) 
{
    int rv = BCM_E_NONE;
    _field_control_t *fc;
    _field_stage_t *stage_fc;
    int (* f)(int, _field_control_t *, _field_stage_t *);
    uint16 version;

#ifdef BCM_TRX_SUPPORT
    if (SOC_IS_TRIUMPH(unit)
        || SOC_IS_VALKYRIE(unit)                   
        || SOC_IS_TRIUMPH2(unit)
        || SOC_IS_APOLLO(unit)
        || SOC_IS_VALKYRIE2(unit)
        || SOC_IS_SC_CQ(unit)
        || SOC_IS_TD_TT(unit)
        || SOC_IS_KATANA(unit)
        ) {
        f = _field_tr2_scache_sync;
    } else
#endif /* BCM_TRX_SUPPORT */
    {
        f = _field_scache_sync;
    }

    if (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
        return BCM_E_NONE;
    }

    /* Get unit FP control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    /* Initialize scache_pos */
    fc->scache_pos = 0;
    
    /* Write the version number */
    version = BCM_WB_DEFAULT_VERSION;
    sal_memcpy(fc->scache_ptr, &version, sizeof(uint16));
    fc->scache_pos += SOC_WB_SCACHE_CONTROL_SIZE;
    
    if (SOC_IS_FIREBOLT(unit) || SOC_IS_FIREBOLT2(unit) || 
        SOC_IS_BRADLEY(unit) || SOC_IS_HUMV(unit) ||
        SOC_IS_RAVEN(unit) || SOC_IS_ENDURO(unit) || 
        SOC_IS_HAWKEYE(unit) || SOC_IS_APOLLO(unit) ||
        SOC_IS_TRIUMPH(unit) || SOC_IS_VALKYRIE(unit) ||
        SOC_IS_TRIUMPH2(unit) || SOC_IS_VALKYRIE2(unit) ||
        SOC_IS_SC_CQ(unit) || SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)
        ) {
        rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS,
                                      &stage_fc);
        
        if (BCM_SUCCESS(rv))
            {
                rv = (*f)(unit, fc, stage_fc);
            }
    }
    
#if  defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (BCM_SUCCESS(rv) &&
        (SOC_IS_FIREBOLT2(unit) || SOC_IS_ENDURO(unit) || 
         SOC_IS_APOLLO(unit) || 
         SOC_IS_TRIUMPH(unit) || SOC_IS_VALKYRIE(unit) ||
         SOC_IS_TRIUMPH2(unit) || SOC_IS_VALKYRIE2(unit) ||
         SOC_IS_SC_CQ(unit) || SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)
         )) {
        rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_EGRESS,
                                      &stage_fc);
        
        if (BCM_SUCCESS(rv)) {
            rv = (*f)(unit, fc, stage_fc);
            
            if (BCM_SUCCESS(rv)) {
                rv = _field_stage_control_get(unit, 
                                              _BCM_FIELD_STAGE_LOOKUP, &stage_fc);
                
                if (BCM_SUCCESS(rv)) {
                    rv = (*f)(unit, fc, stage_fc);
                    
                    if (BCM_SUCCESS(rv) && 
                        soc_feature(unit, soc_feature_esm_support)) {
                        rv = _field_stage_control_get(unit, 
                                                      _BCM_FIELD_STAGE_EXTERNAL, &stage_fc);
                        
                        if (BCM_SUCCESS(rv)) {
                            rv = (*f)(unit, fc, stage_fc);
                        }
                    }
                }
            }
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRIUMPH_SUPPORT */
    
    FP_UNLOCK(fc);
    return rv;
}

STATIC int 
_field_group_entry_write(int unit, int slice_idx, _field_slice_t *fs,
                         _field_control_t *fc, _field_stage_t *stage_fc)
{
    int qset_count, ratio, idx, prev_prio, multigroup, master_slice;
    uint8 stat_present, pol_present, prio_ctrl;
    uint8 *buf = fc->scache_ptr;
    _field_group_t *fg;
    _field_entry_t *f_ent;
    bcm_port_t port;
    bcm_field_qualify_t q;
    bcm_pbmp_t port_cmic_pbmp;
    _field_slice_t *temp_fs = fs;

    SOC_PBMP_ASSIGN(port_cmic_pbmp, PBMP_PORT_ALL(unit));
    SOC_PBMP_OR(port_cmic_pbmp, PBMP_CMIC(unit));

    /* Check for multiple groups in a slice */       
    if (SOC_PBMP_EQ(fs->pbmp, port_cmic_pbmp)) {
        multigroup = 0;
    } else {
        FP_VVERB(("_field_scache_sync:   Multigroup.\n"));
        multigroup = 1;
    }
    FP_VVERB(("_field_scache_sync:   Writing slice %d @ byte %d...\n",
        slice_idx, fc->scache_pos));

    buf[fc->scache_pos] = (slice_idx << 1) | multigroup;
    fc->scache_pos++;

    /* Get the master slice if expanded */
    master_slice = slice_idx;
    while (temp_fs->prev != NULL) {
        temp_fs = temp_fs->prev;
        master_slice = temp_fs->slice_number;
    } 

    /* Traverse all groups and dump group data for this slice */
    fg = fc->groups;
    while (fg != NULL) {
        if (fg->stage_id != stage_fc->stage_id) {
            fg = fg->next;
            continue; /* Not in this stage */
        }
        if (fg->slices[0].slice_number != master_slice) {
            FP_VVERB(("_field_scache_sync:   No match on group %d.\n",
                fg->gid));
            fg = fg->next;
            continue; /* Not in this slice */
        }
        FP_VVERB(("_field_scache_sync:   Match on group %d...\n",
            fg->gid));

        FP_VVERB(("_field_scache_sync:   Writing group %d @ byte %d...\n",
            fg->gid, fc->scache_pos));

        SOC_PBMP_ITER(fg->pbmp, port) {
            break; /* Pick first port found as representative */
        }
        
        if (fc->flags & _FP_STABLE_SAVE_LONG_IDS) {
            /* Long-id format selected => Save full GID */

            buf[fc->scache_pos] = fg->gid;
            fc->scache_pos++;
            buf[fc->scache_pos] = fg->gid >> 8;
            fc->scache_pos++;
            buf[fc->scache_pos] = fg->gid >> 16;
            fc->scache_pos++;
            buf[fc->scache_pos] = fg->gid >> 24;
            fc->scache_pos++;

            buf[fc->scache_pos] = port;
            fc->scache_pos++; 
        } else {
            /* Save compact GID */

            buf[fc->scache_pos] = (fg->gid) & 0xFF; /* GID_lo */
            fc->scache_pos++;
            buf[fc->scache_pos] = ((fg->gid & 0xF00) << 4) | (port & 0xF); 
            fc->scache_pos++; /* GID_hi | port_lo */
            buf[fc->scache_pos] = (port >> 4); /* port_hi */
            fc->scache_pos++; 
        }

        /* Write group priority */ 
        buf[fc->scache_pos] = fg->priority; 
        fc->scache_pos++; 
        buf[fc->scache_pos] = fg->priority >> 8; 
        fc->scache_pos++; 
        buf[fc->scache_pos] = fg->priority >> 16; 
        fc->scache_pos++; 
        buf[fc->scache_pos] = fg->priority >> 24; 
        fc->scache_pos++; 

        /* Obtain list of qualifiers in fg->qset */
        qset_count = 0;
        _FIELD_QSET_INCL_INTERNAL_ITER(fg->qset, q) {
            qset_count++;
        }

        FP_VVERB(("_field_scache_sync:   Writing qset count (%d) @ byte %d...\n",
            qset_count, fc->scache_pos));

        buf[fc->scache_pos] = qset_count; /* qset_count */
        fc->scache_pos++;
        _FIELD_QSET_INCL_INTERNAL_ITER(fg->qset, q) {
            FP_VVERB(("_field_scache_sync:     Writing qid %d @ byte %d...\n",
                q, fc->scache_pos));

            buf[fc->scache_pos] = q; /* QID */
            fc->scache_pos++;
        }
        fg = fg->next;
        if ((fg != NULL)
            && multigroup 
            && (fg->slices[0].slice_number == slice_idx)
            ) {
            buf[fc->scache_pos] = 1; /* Next group valid */
        } else {
            buf[fc->scache_pos] = 0; /* Next group not valid */
        }
        fc->scache_pos++;
        /* Traverse all entries and dump entry data for this slice */
        if (fs->group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            ratio = 2;
        } else {
            ratio = 1;
        }
        prev_prio = -1;
        for (idx = 0; idx < fs->entry_count / ratio; idx++) {
            /* Find EID that matches this HW index */
            f_ent = fs->entries[idx];
            if (f_ent == NULL) {
                continue;
            }
            if (f_ent->flags & _FP_ENTRY_INSTALLED) {
                prio_ctrl = (f_ent->prio != prev_prio) ? 1 : 0;
                stat_present = (f_ent->statistic.flags & 
                                _FP_ENTRY_STAT_INSTALLED) ? 1 : 0;
                pol_present = (f_ent->policer[0].flags & 
                               _FP_POLICER_INSTALLED) ? 1 : 0;
                if (fc->flags & _FP_STABLE_SAVE_LONG_IDS) {
                    /* Long-id format select => Save complete EID */

                    buf[fc->scache_pos] = f_ent->eid;
                    fc->scache_pos++;
                    buf[fc->scache_pos] = f_ent->eid >> 8;
                    fc->scache_pos++;
                    buf[fc->scache_pos] = f_ent->eid >> 16;
                    fc->scache_pos++;
                    buf[fc->scache_pos] = f_ent->eid >> 24;
                    fc->scache_pos++;

                    buf[fc->scache_pos] = prio_ctrl
                        | (stat_present << 1)
                        | (pol_present << 2);
                    fc->scache_pos++;
                } else {
                    /* Save compact EID */

                    buf[fc->scache_pos] = f_ent->eid & 0xFF; /* EID_lo */
                    fc->scache_pos++;
                    buf[fc->scache_pos] = (f_ent->eid >> 8) | (prio_ctrl << 4) |
                        (stat_present << 5) | (pol_present << 6); 
                    /* EID_hi + control bits */
                    fc->scache_pos++;
                }
                if (multigroup) {
                    /* Multiple groups in slice => Save id of group to which
                       entry belongs
                    */

                    if (fc->flags & _FP_STABLE_SAVE_LONG_IDS) {
                        /* Save long GID */

                        buf[fc->scache_pos] = f_ent->group->gid;
                        fc->scache_pos++;
                        buf[fc->scache_pos] = f_ent->group->gid >> 8;
                        fc->scache_pos++;
                        buf[fc->scache_pos] = f_ent->group->gid >> 16;
                        fc->scache_pos++;
                        buf[fc->scache_pos] = f_ent->group->gid >> 24;
                        fc->scache_pos++;
                    } else {
                        /* Save compact GID */

                        buf[fc->scache_pos] = f_ent->group->gid & 0xFF; /* GID_lo */
                        fc->scache_pos++;
                        buf[fc->scache_pos] = (f_ent->group->gid >> 8) & 0xF; 
                        /* GID_hi */
                        fc->scache_pos++;
                    }
                } 
                if (prio_ctrl) {
                    /* 32-bit priority is written */
                    buf[fc->scache_pos] = f_ent->prio & 0xFF;
                    fc->scache_pos++;
                    buf[fc->scache_pos] = (f_ent->prio >> 8) & 0xFF;
                    fc->scache_pos++;
                    buf[fc->scache_pos] = (f_ent->prio >> 16) & 0xFF;
                    fc->scache_pos++;
                    buf[fc->scache_pos] = (f_ent->prio >> 24) & 0xFF;
                    fc->scache_pos++;
                    prev_prio = f_ent->prio;
                }
                /* Write policer and stat object IDs if present */
                if (fc->flags & _FP_STABLE_SAVE_LONG_IDS) {
                    /* Save long IDs */

                    if (pol_present) {
                        buf[fc->scache_pos] = f_ent->policer[0].pid;
                        fc->scache_pos++;
                        buf[fc->scache_pos] = f_ent->policer[0].pid >> 8;
                        fc->scache_pos++;
                        buf[fc->scache_pos] = f_ent->policer[0].pid >> 16;
                        fc->scache_pos++;
                        buf[fc->scache_pos] = f_ent->policer[0].pid >> 24;
                        fc->scache_pos++;
                    }

                    if (stat_present) {
                        buf[fc->scache_pos] = f_ent->statistic.sid;
                        fc->scache_pos++;
                        buf[fc->scache_pos] = f_ent->statistic.sid >> 8;
                        fc->scache_pos++;
                        buf[fc->scache_pos] = f_ent->statistic.sid >> 16;
                        fc->scache_pos++;
                        buf[fc->scache_pos] = f_ent->statistic.sid >> 24;
                        fc->scache_pos++;
                    }
                } else {
                    /* Save compact IDs */
                    if (pol_present) {
                        buf[fc->scache_pos] = (f_ent->policer[0].pid) & 0xFF;   
                        fc->scache_pos++;
                    }
                    if (stat_present) {
                        if (pol_present) {
                            buf[fc->scache_pos] = 
                                ((f_ent->policer[0].pid >> 8 & 0xF) << 4) | 
                                (f_ent->statistic.sid & 0xF);
                            fc->scache_pos++;
                        } else {
                            buf[fc->scache_pos] = f_ent->statistic.sid & 0xF;
                            fc->scache_pos++;
                        }
                        buf[fc->scache_pos] = (f_ent->statistic.sid >> 4) & 0xFF;
                        fc->scache_pos++;
                    } else if (pol_present) {
                        buf[fc->scache_pos] = 
                            (f_ent->policer[0].pid >> 8 & 0xF) << 4;
                        fc->scache_pos++;
                    }
                }
            }
        }
        /* Mark next slice valid */
    }
    return BCM_E_NONE;
}

/*
 * This function manages the Level 2 warm boot cache. The data will be stored 
 * in the following format:
 * Start indicator (32 bits): Value = IFP/EFP/VFP
 *
 * Range check IDs (IFP)
 * 8-bit ID count (1 uint8)
 * ID0 (4 x uint8)
 * .
 * IDN (4 x uint8)
 *
 * Data qualifier data, as follows:
 * 8-bit data qualifier count (1 uint 8)
 * 32-bit data qualifier id (1 int)
 * 2-bit "length remainder" | 3-bit flags | 3-bit offset base (1 uint 8)
 * 16-bit data qualifier match-data offset (1 uint 16)
 * 16-bit hw_bmap field of data qualifier
 *   (Note that this field is linked to the hardware; namely, the width of this
 *   bitmap is the number of UDF n-byte chunks supported, i.e. the number of
 *   "columns" in the UDF_OFFSET table.)
 *
 * Group/entry data
 * Slice num (5 bits) | Multigroup slice indicator (1 bit): (1 uint8)
 * GID_lo (8 bits): (1 uint 8)
 * GID_hi (4 bits) | Representative_port_lo (4 bits): (1 uint 8)
 * Representative_port_hi (2 bits) | Reserved (6 bits): (1 uint 8)
 * Group priority (32 bits): (4 uint 8)
 * Qualifier count (8 bits): (1 uint 8)
 * QID 1 (8 bits): (1 uint 8)
 * .
 * QID N (8 bits): (1 uint 8)
 * Next_group_valid (1 bit) | Reserved (7 bits): (1 uint 8)
 * 
 * Groups are immediately followed by entries, which can have one of the 
 * following two formats depending on the multigroup slice indicator:
 * Long format:
 * 8 bit EID_lo: (1 uint 8)
 * 4 bit EID_hi | priority_ctrl (1 bit) | Policer (1 bit) | Stat (1 bit): 
  (1 uint 8) 
 * 8 bit GID_lo: (1 uint 8)
 * 4 bit GID_hi | 4 reserved bits: (1 uint 8) 
 * priority_0: (1 uint 8) 
 * priority_1: (1 uint 8) <---- The 32-bit priority is stored only if it is
 * priority_2: (1 uint 8)       different from the entry before it.
 * priority_3: (1 uint 8)
 * PID_lo (8 bits): (1 uint8)
 * PID_hi (4 bits) | SID_lo (4 bits): (1 uint8)
 * SID_hi (4 bits): (1 uint 8)
 * Short format:
 * 8 bit EID_lo: (1 uint 8)
 * 4 bit EID_hi | priority_ctrl (1 bit) | Policer (1 bit) | Stat (1 bit): 
  (1 uint 8) 
 * priority_0: (1 uint 8) 
 * priority_1: (1 uint 8) <---- The 32-bit priority is stored only if it is
 * priority_2: (1 uint 8)       different from the entry before it.
 * priority_3: (1 uint 8)
 * PID_lo (8 bits): (1 uint8)
 * PID_hi (4 bits) | SID_lo (4 bits): (1 uint8)
 * SID_hi (8 bits): (1 uint 8)
 *
 * End indicator (32 bits): Value = IFP/EFP/VFP
 */

void
_field_scache_stage_hdr_save(_field_control_t *fc,
                             uint32           header
                             )
{
    uint8  *buf = fc->scache_ptr;

    /* Mark the beginning of the particular FP section */
    buf[fc->scache_pos] = header;
    fc->scache_pos++;
    buf[fc->scache_pos] = header >> 8;
    fc->scache_pos++;
    buf[fc->scache_pos] = header >> 16;
    fc->scache_pos++;
    buf[fc->scache_pos] = header >> 24;
    fc->scache_pos++;

    /* Save long-id setting */

    buf[fc->scache_pos] = fc->flags;
    fc->scache_pos++;
}

int
_field_scache_stage_hdr_chk(_field_control_t *fc,
                            uint32           header
                            )
{
    uint8  *buf = fc->scache_ptr;
    uint16 version;
    uint32 temp;

    /* Check header */

    temp = buf[fc->scache_pos];
    fc->scache_pos++;
    temp |= buf[fc->scache_pos] << 8;
    fc->scache_pos++;
    temp |= buf[fc->scache_pos] << 16;
    fc->scache_pos++;
    temp |= buf[fc->scache_pos] << 24;
    fc->scache_pos++;
    if (temp != header) {
        fc->l2warm = 0;
        
        return (BCM_E_INTERNAL);
    }
    
    sal_memcpy(&version, fc->scache_ptr, sizeof(version));

    if (version == BCM_WB_VERSION_1_0) {
        /* Old scache version, always uses compact ids */

        fc->flags &= ~_FP_STABLE_SAVE_LONG_IDS;
    } else {
        /* Retrieve long-id setting */
        
        if (buf[fc->scache_pos] & _FP_STABLE_SAVE_LONG_IDS) {
            fc->flags |= _FP_STABLE_SAVE_LONG_IDS;
        } else {
            fc->flags &= ~_FP_STABLE_SAVE_LONG_IDS;
        }

        /* Retrieve Intra-slice device setting */
        if (buf[fc->scache_pos] & _FP_INTRASLICE_ENABLE) {
            fc->flags |= _FP_INTRASLICE_ENABLE;
        } else {
            fc->flags &= ~_FP_INTRASLICE_ENABLE;
        }

        /* Retrieve color independent device setting */
        if (buf[fc->scache_pos] & _FP_COLOR_INDEPENDENT) {
            fc->flags |= _FP_COLOR_INDEPENDENT;
        } else {
            fc->flags &= ~_FP_COLOR_INDEPENDENT;
        }
        fc->scache_pos++;
    }
        
    return (BCM_E_NONE);
}

void
_field_scache_sync_data_quals_write(_field_control_t      *fc,
                                    _field_data_control_t *data_ctrl
                                    )
{
    uint8                   *buf = fc->scache_ptr;
    unsigned                cnt;
    _field_data_qualifier_t *f_dq;

    /* Write data qual count */

    for (cnt = 0, f_dq = data_ctrl->data_qual; f_dq; f_dq = f_dq->next, ++cnt);
        
    buf[fc->scache_pos] = cnt;
    fc->scache_pos++;
    
    /* For each data qualifier, ... */
    for (f_dq = data_ctrl->data_qual; f_dq; f_dq = f_dq->next) {
        /* Write data qual id */
        
        buf[fc->scache_pos] = f_dq->qid;
        fc->scache_pos++;
        buf[fc->scache_pos] = f_dq->qid >> 8;
        fc->scache_pos++;
        buf[fc->scache_pos] = f_dq->qid >> 16;
        fc->scache_pos++;
        buf[fc->scache_pos] = f_dq->qid >> 24;
        fc->scache_pos++;
        
        /* Write data qual "length remainder", flags and offset base */
        buf[fc->scache_pos] = ((f_dq->elem_count * data_ctrl->elem_size
                                - f_dq->length
                                - f_dq->byte_offset
                                ) << 6
                               )
            | (f_dq->flags << 1)
            | f_dq->offset_base;
        fc->scache_pos++;            
        
        /* Write data qual match-data offset */
        buf[fc->scache_pos] = f_dq->offset;
        fc->scache_pos++;
        buf[fc->scache_pos] = f_dq->offset >> 8;
        fc->scache_pos++;
        
        /* Write data qual offset-table occupancy */
        buf[fc->scache_pos] = f_dq->hw_bmap;
        fc->scache_pos++;
        buf[fc->scache_pos] = f_dq->hw_bmap >> 8;
        fc->scache_pos++;
    }
}


int
_field_scache_sync(int unit, _field_control_t *fc,
                   _field_stage_t *stage_fc)
{
    int slice_idx, range_count = 0;
    int rv = BCM_E_NONE;
    uint8 *buf = fc->scache_ptr;
    _field_slice_t *fs;
    _field_group_t *fg;
    uint32 start_char, end_char;
    int slice_is_primary;
    int slice_mode;
    _field_range_t *fr;

    switch (stage_fc->stage_id) {
    case _BCM_FIELD_STAGE_INGRESS:
        start_char = _FIELD_IFP_DATA_START;
        end_char = _FIELD_IFP_DATA_END;
        break;
    case _BCM_FIELD_STAGE_EGRESS:
        start_char = _FIELD_EFP_DATA_START;
        end_char = _FIELD_EFP_DATA_END;
        break;
    case _BCM_FIELD_STAGE_LOOKUP:
        start_char = _FIELD_VFP_DATA_START;
        end_char = _FIELD_VFP_DATA_END;
        break;
    default:
        return BCM_E_PARAM;
        break;
    }

    FP_VVERB(("_field_scache_sync: Synching scache for FP stage %d...\n", 
        stage_fc->stage_id));

    _field_scache_stage_hdr_save(fc, start_char);

    /* Save the range check IDs */
    if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
        fr = stage_fc->ranges;
        while (fr) {
            fr = fr->next;
            range_count++;
        }
        buf[fc->scache_pos] = (uint8)range_count;
        fc->scache_pos++;
        if (range_count) {
            fr = stage_fc->ranges;
            while (fr) {
                buf[fc->scache_pos] = fr->rid & 0xFF;
                fc->scache_pos++;
                buf[fc->scache_pos] = (fr->rid >> 8) & 0xFF;
                fc->scache_pos++;
                buf[fc->scache_pos] = (fr->rid >> 16) & 0xFF;
                fc->scache_pos++;
                buf[fc->scache_pos] = (fr->rid >> 24) & 0xFF;
                fc->scache_pos++;
                fr = fr->next;
            }
        }
    }

    /* Save data qualifiers */

    if (stage_fc->data_ctrl != 0) {
        _field_scache_sync_data_quals_write(fc, stage_fc->data_ctrl);
    }

    /* First sync the master slices */
    for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
        FP_VVERB(("_field_scache_sync: Checking slice %d...\n", slice_idx));

        fs = stage_fc->slices + slice_idx; 
        /* Skip slices without groups */
        fs = stage_fc->slices + slice_idx; 
        fg = fc->groups;
        while (fg != NULL) {
            if (fg->stage_id != stage_fc->stage_id) {
                fg = fg->next;
                continue; /* Not in this stage */
            }
            if (fg->slices[0].slice_number == slice_idx) {
                break;
            }
            fg = fg->next;
        }
        if (fg == NULL) {
            continue; /* No group found */
        }
        /* Also skip expanded slices */
        if (stage_fc->slices[slice_idx].prev != NULL) {
            continue;
        }
        /* Ignore secondary slice in paired mode */
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_ENDURO_SUPPORT) || defined(BCM_KATANA_SUPPORT)
        if (SOC_IS_FIREBOLT2(unit) || SOC_IS_ENDURO(unit) || SOC_IS_KATANA(unit)) {
            soc_field_t fld;
            int efp_slice_mode, paired = 0;
            uint32 val;
            fp_port_field_sel_entry_t pfs;
            soc_field_t _fb2_slice_pairing_field[8] = {
                                  SLICE1_0_PAIRINGf,   SLICE3_2_PAIRINGf,
                                  SLICE5_4_PAIRINGf,   SLICE7_6_PAIRINGf,
                                  SLICE9_8_PAIRINGf,   SLICE11_10_PAIRINGf,
                                  SLICE13_12_PAIRINGf, SLICE15_14_PAIRINGf};
            soc_field_t _efp_slice_mode[] = {SLICE_0_MODEf, SLICE_1_MODEf,
                                             SLICE_2_MODEf, SLICE_3_MODEf};
            soc_field_t _vfp_slice_pairing_field[2] = {SLICE1_0_PAIRINGf,
                                                       SLICE3_2_PAIRINGf};
            switch (stage_fc->stage_id) {
            case _BCM_FIELD_STAGE_INGRESS:
                BCM_IF_ERROR_RETURN(soc_mem_read(unit, FP_PORT_FIELD_SELm, 
                                                 MEM_BLOCK_ANY, 0, &pfs));
                fld = _fb2_slice_pairing_field[slice_idx / 2];
                paired = soc_FP_PORT_FIELD_SELm_field32_get(unit, 
                                                            &pfs, fld);
                break;
            case _BCM_FIELD_STAGE_EGRESS:
                BCM_IF_ERROR_RETURN(READ_EFP_SLICE_CONTROLr(unit, &val));
                efp_slice_mode = soc_reg_field_get(unit, EFP_SLICE_CONTROLr, 
                                                val,_efp_slice_mode[slice_idx]);
                if ((efp_slice_mode == _BCM_FIELD_EGRESS_SLICE_MODE_DOUBLE)) {
                    paired = 1;
                }
                break;
            case _BCM_FIELD_STAGE_LOOKUP:
                BCM_IF_ERROR_RETURN(READ_VFP_KEY_CONTROLr(unit, &val));
                fld = _vfp_slice_pairing_field[slice_idx / 2];
                paired = soc_reg_field_get(unit, VFP_KEY_CONTROLr, val, fld);
                break;
            default:
                return BCM_E_PARAM;
                break;
            }
            if (paired && (slice_idx % 2)) {
                continue;
            }
        }
#endif /* BCM_FIREBOLT2_SUPPORT */

#ifdef BCM_FIREBOLT_SUPPORT
        if (SOC_IS_FIREBOLT(unit))
        {
            BCM_IF_ERROR_RETURN(_field_fb_slice_is_primary(unit, slice_idx,
                &slice_is_primary, &slice_mode));

            if (!slice_is_primary)
            {
                continue;
            }
        }
#endif /* BCM_FIREBOLT_SUPPORT */

#ifdef BCM_RAVEN_SUPPORT
        if (SOC_IS_RAVEN(unit) || SOC_IS_HAWKEYE(unit))
        {
            BCM_IF_ERROR_RETURN(_field_fb_slice_is_primary(unit, slice_idx,
                &slice_is_primary, &slice_mode));

            if (!slice_is_primary)
            {
                continue;
            }
        }
#endif /* BCM_RAVEN_SUPPORT */
        BCM_IF_ERROR_RETURN
            (_field_group_entry_write(unit, slice_idx, fs, fc, stage_fc));
    }

    /* Now sync the expanded slices */
    for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
        fs = stage_fc->slices + slice_idx; 
        /* Skip empty slices */
        if (fs->entry_count == fs->free_count) {
            FP_VVERB(("_field_scache_sync:   Slice is empty.\n"));
            continue;
        }
        /* Skip master slices */
        if (stage_fc->slices[slice_idx].prev == NULL) {
            continue;
        }
        BCM_IF_ERROR_RETURN
            (_field_group_entry_write(unit, slice_idx, fs, fc, stage_fc));
    }

    FP_VVERB(("_field_scache_sync: Writing end of section @ byte %d.\n",
        fc->scache_pos));

    /* Mark the end of the IFP section */
    buf[fc->scache_pos] = end_char & 0xFF;
    fc->scache_pos++;
    buf[fc->scache_pos] = (end_char >> 8) & 0xFF;
    fc->scache_pos++;
    buf[fc->scache_pos] = (end_char >> 16) & 0xFF;
    fc->scache_pos++;
    buf[fc->scache_pos] = (end_char >> 24) & 0xFF;
    fc->scache_pos++;
    fc->scache_usage = fc->scache_pos; /* Usage in bytes */
    return rv;
}

/* Recover FP data qualifiers */

int
_field_data_qual_recover(int              unit,
                         _field_control_t *fc, 
                         _field_stage_t   *stage_fc
                         )
{
    _field_data_control_t          *data_ctrl;
    uint8                          *buf;
    unsigned                       dqcnt, n, i, len_rem;
    _field_data_qualifier_t        *f_dq;

    if ((data_ctrl = stage_fc->data_ctrl) == 0) {
        return (BCM_E_NONE);
    }

    if (fc->l2warm == 0) {
        /* No data qualifier recovery in Level 1 */
        return BCM_E_NONE;
    }

    buf = fc->scache_ptr;

#if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT)

    if (soc_mem_is_valid(unit, FP_UDF_TCAMm)) {
        /* Device has UDF TCAM =>
           Recover internal information regarding TCAM entry usage
        */

        int                            rv;
        fp_udf_tcam_entry_t            fp_udf_tcam_entry;
        _field_data_tcam_entry_t       *tcam_entryp;
        bcm_field_data_packet_format_t pkt_fmt;
        
        /* Recover TCAM entry reference counts and priorities */
        for (tcam_entryp = data_ctrl->tcam_entry_arr,
                 i = 0,
                 n = soc_mem_index_count(unit, FP_UDF_TCAMm);
             n;
             --n, ++i, ++tcam_entryp) {
            tcam_entryp->ref_count = buf[fc->scache_pos];
            fc->scache_pos++;
            
            BCM_IF_ERROR_RETURN(soc_mem_read(unit,
                                             FP_UDF_TCAMm,
                                             MEM_BLOCK_ANY,
                                             i,
                                             fp_udf_tcam_entry.entry_data
                                             )
                                );
            
            if (tcam_entryp->ref_count == 0) {
                /* TCAM entry is not in use */
                
                /* Consistency check: the valid bit for the TCAM entry
                   better be cleared!
                */
                if (soc_mem_field32_get(unit,
                                        FP_UDF_TCAMm,
                                        fp_udf_tcam_entry.entry_data,
                                        VALIDf
                                        )
                    != 0
                    ) {
                    return (BCM_E_INTERNAL);
                }
                
                continue;
            }
            
            /* TCAM entry is in use */
            
            /* Consistency check: the valid bit for the TCAM entry
               better be set!
            */
            if (soc_mem_field32_get(unit,
                                    FP_UDF_TCAMm,
                                    fp_udf_tcam_entry.entry_data,
                                    VALIDf
                                    )
                == 0
                ) {
                return (BCM_E_INTERNAL);
            }
            
            /* Parse l2 format.*/
            rv = _field_trx2_udf_tcam_entry_l2format_parse(
                     unit,
                     fp_udf_tcam_entry.entry_data,
                     &pkt_fmt.l2
                                                           );
            BCM_IF_ERROR_RETURN(rv);
            
            /* Parse vlan_tag format.*/
            rv = _field_trx2_udf_tcam_entry_vlanformat_parse(
                     unit,
                     fp_udf_tcam_entry.entry_data,
                     &pkt_fmt.vlan_tag
                                                             );
            BCM_IF_ERROR_RETURN(rv);
            
            /* Parse l3 fields.*/
            rv = _field_trx2_udf_tcam_entry_l3_parse(
                      unit,
                      fp_udf_tcam_entry.entry_data,
                      &pkt_fmt
                                                     );
            BCM_IF_ERROR_RETURN(rv);
            
            /* Recover TCAM entry priority */
            tcam_entryp->priority = 0;
            if (pkt_fmt.l2 != BCM_FIELD_DATA_FORMAT_L2_ANY) {
                /* L2 format was specified */
                
                tcam_entryp->priority += _FP_DATA_QUALIFIER_PRIO_L2_FORMAT;
            }
            
            if (pkt_fmt.vlan_tag != BCM_FIELD_DATA_FORMAT_VLAN_TAG_ANY) {
                /* Vlan tag format was specified */
                
                tcam_entryp->priority += _FP_DATA_QUALIFIER_PRIO_VLAN_FORMAT;
            }
            
            if (pkt_fmt.tunnel == BCM_FIELD_DATA_FORMAT_TUNNEL_FCOE
                || pkt_fmt.tunnel == BCM_FIELD_DATA_FORMAT_TUNNEL_FCOE_INIT
                ) {
                tcam_entryp->priority += _FP_DATA_QUALIFIER_PRIO_FCOE_FORMAT;

                /* 
                 * Entry matching on Outer + Inner FCOE extended headers has
                 * higher priority.
                 */
                if (0 != pkt_fmt.fibre_chan_outer
                    && 0 != pkt_fmt.fibre_chan_inner) {
                    tcam_entryp->priority += _FP_DATA_QUALIFIER_PRIO_FCOE_FORMAT;
                }
            } else if (pkt_fmt.tunnel == BCM_FIELD_DATA_FORMAT_TUNNEL_NONE
                && pkt_fmt.outer_ip == BCM_FIELD_DATA_FORMAT_IP_ANY
                && pkt_fmt.inner_ip == BCM_FIELD_DATA_FORMAT_IP_NONE
                ) {
                /* Entry corresponds to a call to
                   bcm_field_data_qualifier_ip_protocol_add() or
                   bcm_field_data_qualifier_ethertype_add()
                */
                
                tcam_entryp->priority += _FP_DATA_QUALIFIER_PRIO_MISC;
            } else {
                /* Entry corresponds to a call to
                   bcm_field_data_qualifier_packet_format_add()
                */
                
                tcam_entryp->priority += _FP_DATA_QUALIFIER_PRIO_L3_FORMAT;
            }
        }
    }

#endif /* defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT) */

    for (dqcnt = buf[fc->scache_pos++]; dqcnt; --dqcnt) {
        _bcm_field_data_qualifier_alloc(unit, &f_dq);
        
        /* Read data qual id */
        
        f_dq->qid = buf[fc->scache_pos];
        fc->scache_pos++;
        f_dq->qid |= buf[fc->scache_pos] << 8;
        fc->scache_pos++;
        f_dq->qid |= buf[fc->scache_pos] << 16;
        fc->scache_pos++;
        f_dq->qid |= buf[fc->scache_pos] << 24;
        fc->scache_pos++;
        
        /* Read data qual "length remainder", flags and offset base */
        len_rem           = buf[fc->scache_pos] >> 6;
        f_dq->flags       = (buf[fc->scache_pos] >> 1)
            & _BCM_FIELD_DATA_QUALIFIER_FLAGS;
        f_dq->offset_base = buf[fc->scache_pos] & 7;
        fc->scache_pos++;

        /* Read data qual match-data offset */
        f_dq->offset = buf[fc->scache_pos];
        fc->scache_pos++;
        f_dq->offset |= buf[fc->scache_pos] << 8;
        fc->scache_pos++;
        
        /* Read data qual hw_bmap */
        f_dq->hw_bmap = buf[fc->scache_pos];
        fc->scache_pos++;
        f_dq->hw_bmap |= buf[fc->scache_pos] << 8;
        fc->scache_pos++;
        
        /* Find number of elements used */
        for (f_dq->elem_count = i = 0, n = BCM_FIELD_USER_MAX_DQS;
             n;
             --n, ++i
             ) {
            if (f_dq->hw_bmap & (1U << i)) {
                ++f_dq->elem_count;
            }
        }
        
        /* Consistency check: hw_bmap should not be 0! */
        if (f_dq->elem_count == 0) {
            _bcm_field_data_qualifier_free(unit, f_dq);

            return (BCM_E_INTERNAL);
        }
        
        _field_data_qualifier_init2(unit, stage_fc, f_dq);
        
        f_dq->length = f_dq->elem_count * data_ctrl->elem_size
            - f_dq->byte_offset
            - len_rem;

        /* N.B.  fq->flags is not applicable for Triumph2 => Leave as 0 */
        
        /* Merge qualifier's hw_bmap into overall uasge bmap */
        data_ctrl->usage_bmap |= f_dq->hw_bmap;
    }

    return (BCM_E_NONE);
}


/* Update a qset's udf_bmap to reflect actual data qualifier usage. */

void
_field_qset_udf_bmap_reinit(int              unit,
                            _field_stage_t   *stage_fc,
                            bcm_field_qset_t *qset,
                            int              qual_id
                            )
{
    _field_data_qualifier_t *f_dq;
    unsigned                elem_idx, n;
    
#if defined(BCM_ENDURO_SUPPORT)
    if(SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit)) {
        if (qual_id < _bcmFieldQualifyData0 || qual_id > _bcmFieldQualifyData3) {
            return;
        }
    } else
#endif /* BCM_ENDURO_SUPPORT */
    {
        if (qual_id < _bcmFieldQualifyData0 || qual_id > _bcmFieldQualifyData1) {
            return;
        }
    }

    for (f_dq = stage_fc->data_ctrl->data_qual; f_dq; f_dq = f_dq->next) {
        for (elem_idx = 0, n = stage_fc->data_ctrl->num_elems * 2; n; --n, ++elem_idx) {
            if ((f_dq->hw_bmap & (1U << elem_idx)) == 0) {
                continue;
            }
            
            SHR_BITSET(qset->udf_map, elem_idx);
        }
    }
}


/* Recover range chackers */
int
_field_range_check_reinit(int unit, _field_stage_t *stage_fc, 
                          _field_control_t *fc)
{
    int idx, index_min, index_max, count, valid_count;
    uint32 enable, type;
    soc_mem_t mem;
    uint32 tbl_entry[SOC_MAX_MEM_FIELD_WORDS];
    _field_range_t *fr, **last_fr;
    uint8 *buf = fc->scache_ptr;

    count = valid_count = 0;
    if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
        mem = FP_RANGE_CHECKm;
    } else {
        mem = ESM_RANGE_CHECKm;
    }
    if (fc->l2warm) {
        count = buf[fc->scache_pos];
        fc->scache_pos++;
    }

    last_fr = &stage_fc->ranges;
    index_min = soc_mem_index_min(unit, mem);
    index_max = soc_mem_index_max(unit, mem);
    for (idx = index_min; idx <= index_max; idx ++) {
        sal_memset(tbl_entry, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
        BCM_IF_ERROR_RETURN
            (soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, tbl_entry));
        soc_mem_field_get(unit, mem, tbl_entry, ENABLEf, &enable); 
        if (enable == 0) {
            continue;
        }
        valid_count++;
        /* Create a new range entry for the list */
        if ((fr = sal_alloc(sizeof (*fr), "fp_range")) == NULL) {
            return (BCM_E_MEMORY);
        }
        sal_memset(fr, 0, sizeof(_field_range_t));
        /* Populate the structure */
        if (fc->l2warm) {
            /* Get the IDs */
            fr->rid = 0;
            fr->rid |= buf[fc->scache_pos];
            fc->scache_pos++;
            fr->rid |= buf[fc->scache_pos] << 8;
            fc->scache_pos++;
            fr->rid |= buf[fc->scache_pos] << 16;
            fc->scache_pos++;
            fr->rid |= buf[fc->scache_pos] << 24;
            fc->scache_pos++;
        } else {
            fr->rid = idx;
        }
        fr->hw_index = idx;
        fr->style = _FP_RANGE_STYLE_FIREBOLT;
        soc_mem_field_get(unit, mem, tbl_entry, LOWER_BOUNDSf, 
                          (uint32 *)&(fr->min));
        soc_mem_field_get(unit, mem, tbl_entry, UPPER_BOUNDSf, 
                          (uint32 *)&(fr->max));
        if ((SOC_MEM_FIELD_VALID(unit, mem, FIELD_SELECTf))) {
            soc_mem_field_get(unit, mem, tbl_entry, FIELD_SELECTf, &type);
            switch (type) {
            case 0:
                fr->flags |= BCM_FIELD_RANGE_SRCPORT;
                break;
            case 1:
                fr->flags |= BCM_FIELD_RANGE_DSTPORT;
                break;
            case 2:
                fr->flags |= BCM_FIELD_RANGE_OUTER_VLAN;
                break;
            case 3:
                fr->flags |= BCM_FIELD_RANGE_PACKET_LENGTH;
                break;
            default:
                break; /* Should never happen */
            }
        } else {
            soc_mem_field_get(unit, mem, tbl_entry, 
                              SOURCE_DESTINATION_SELECTf, &type);
            if (type == 1) {
                fr->flags |= BCM_FIELD_RANGE_SRCPORT;
            } else {
                fr->flags |= BCM_FIELD_RANGE_DSTPORT;
            }
        } 

        /* Add to list of range checkers. */
        
        *last_fr = fr;
        last_fr = &fr->next;
    }
    if (fc->l2warm && count != valid_count) {
        return BCM_E_INTERNAL;
    }
    return BCM_E_NONE;
}

#endif /*  BCM_WARM_BOOT_SUPPORT */

/* Given en EID, find the group */
/* Used in various _qualify APIs */
STATIC int
_bcm_field_entry_group_find(int unit, bcm_field_entry_t eid, 
                            _field_group_t **group_p)
{
    int                 idx;          /* Entry index */
    _field_control_t    *fc;          /* Unit FP control structure. */
    _field_group_t      *fg;          /* Group information.         */
    _field_entry_t      *f_ent;       /* Field entry info */

    if (NULL == group_p) {
        return (BCM_E_PARAM);
    }

    /* Get unit FP control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Iterate over the groups linked-list */
    fg = fc->groups;
    while (fg != NULL) {
        /* Now iterate over the entries in this group */
        for (idx = 0; idx < fg->group_status.entry_count; idx++) {
           f_ent = fg->entry_arr[idx];
           if (f_ent->eid == eid) {
               *group_p = fg;
               return BCM_E_NONE;
           } 
        }
        fg = fg->next;
    }
    /* Group with eid not found. */
    return (BCM_E_NOT_FOUND);

}

/*
 * Function:
 *     _bcm_field_action_dest_check
 * Purpose:
 *     Verify destination prameters for fp actions
 * Parameters:
 *     unit    - (IN) BCM device number
 *     fa      - (IN) Field action structure.
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_action_dest_check(int unit, _field_action_t *fa)
{
    int port_out;     /* Calculated port value.    */
    int modid_out;    /* Calculated module id.     */
    int rv;           /* Operation return value.   */ 

    /* Input parameters check. */
    if (NULL == fa) {
        return (BCM_E_PARAM);
    }

    /* No checks for Mirror/Mpls/Mim/Wlan gports  */
    if (BCM_GPORT_IS_SET(fa->param[1])) {
        return (BCM_E_NONE);
    }

    /* Modport/Trunk were resolved in _field_params_api_to_hw_adapt call.*/ 
    if (bcmFieldActionRedirectTrunk == fa->action) {
        return  _bcm_trunk_id_validate(unit, fa->param[0]);
    }

    /* Check destination module id / port. */
    rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
                                fa->param[0], fa->param[1],
                                &modid_out, &port_out);
    BCM_IF_ERROR_RETURN(rv);

    if (!SOC_MODID_ADDRESSABLE(unit, modid_out)) {
        return (BCM_E_PARAM);
    }
    if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
        return (BCM_E_PORT);
    }
    return (BCM_E_NONE);
}

#ifdef INCLUDE_L3
/*
 * Function:
 *     _bcm_field_policy_set_l3_nh_resolve
 * Purpose:
 *     Install l3 forwarding policy entry.  
 * Parameters:
 *     unit      - (IN) BCM device number
 *     mem       - (IN) Policy table memory. 
 *     value     - (IN) Egress object id or combined next hop information.
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_policy_set_l3_nh_resolve(int unit,  int value, 
                                    uint32 *flags, int *nh_ecmp_id)
{
    int rv;           /* Operation return value.    */ 

    /* Check if egress forwarding mode is enabled. */
    rv = bcm_xgs3_l3_egress_id_parse(unit, value, flags, nh_ecmp_id);
    if (rv == BCM_E_DISABLED) {
        if (_FP_L3_ACTION_UNPACK_ECMP_MODE((value))) {
            *flags = BCM_L3_MULTIPATH;
            *nh_ecmp_id = _FP_L3_ACTION_UNPACK_ECMP_PTR((value));
        } else {
            *flags = 0;
            *nh_ecmp_id = _FP_L3_ACTION_UNPACK_NEXT_HOP((value));
        }
        rv = BCM_E_NONE;
    } 
    return (rv);
}

/*
 * Function:
 *     _bcm_field_l2_actions_nh_desroy
 *
 * Purpose:
 *     Free l3 next hop and egress interface for
 *     l2 fields update action.
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     nh_index - (IN) Next hop index.
 *     egr_intf_set - (IN) Egress interface allocated.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_bcm_field_l2_actions_nh_destroy(int unit, int nh_index, int egr_intf_set)
{
    uint32 hw_buf[SOC_MAX_MEM_FIELD_WORDS]; /* hw entry  buffer.            */
    bcm_l3_egress_t egr;                    /* Egress forwarding object.    */
    uint32 intf;                            /* Egress L3 interface id.      */

    /* Initialization. */
    bcm_l3_egress_t_init(&egr);

    /* Read next hop. */
    sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, SOC_BLOCK_ANY,
        nh_index, hw_buf));

    /* clear egress interface information + free interface resource */ 
    if ((1 == egr_intf_set) ||
        (SOC_IS_TRIUMPH2(unit) || SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit) ||
        SOC_IS_APOLLO(unit) || SOC_IS_ENDURO(unit))) {
        /* Get interface id. */
        intf = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, hw_buf, INTF_NUMf);
        /* Reset interface entry in hw. */
        sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
        BCM_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_INTFm, SOC_BLOCK_ALL,
            intf, hw_buf));
        /* Free interface id. */
       BCM_IF_ERROR_RETURN(_bcm_xgs3_egress_l3_intf_id_free(unit, intf));
    }

    /* clear egress next hop table information + free next hop index */
    sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    BCM_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOPm,
        SOC_BLOCK_ALL, nh_index, hw_buf));
    
    BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_index));
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_l2_actions_nh_create
 *
 * Purpose:
 *     Free l3 next hop and egress interface for
 *     l2 fields update action.
 * Parameters:
 *     unit    - (IN) BCM device number.
 *     da_fa   - (IN) Update destination mac action.
 *     sa_fa   - (IN) Update source mac action.
 *     vid_fa  - (IN) Update outer vid action.
 *     vn_new_fa  - (IN) Change VN tag action.
 *     vn_del_fa  - (IN) Delete VN tag action.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_bcm_field_l2_actions_nh_create(int unit, _field_action_t *da_fa,
                                _field_action_t *sa_fa,
                                _field_action_t *vid_fa,
                                _field_action_t *vn_new_fa,
                                _field_action_t *vn_del_fa)
{
    uint32 hw_buf[SOC_MAX_MEM_FIELD_WORDS]; /* hw entry  buffer.     */
    bcm_l3_egress_t egr;            /* Egress forwarding object.     */
    bcm_l3_intf_t  intf;            /* Egress L3 interface id.       */
    int nh_index;                   /* Next hop index.               */
    int nh_flags = 0;               /* Next hop flags.               */
    int tmp_rv = BCM_E_NONE;        /* Operation return status.      */
    int rv = BCM_E_NONE;            /* Operation return status.      */

    /* Initialization. */
    bcm_l3_egress_t_init(&egr);
    bcm_l3_intf_t_init(&intf);

    /* Extract the policy info from the entry structure. */
    if (NULL != da_fa) {
        SAL_MAC_ADDR_FROM_UINT32(egr.mac_addr, da_fa->param);
    }

    if (NULL != sa_fa) {
        SAL_MAC_ADDR_FROM_UINT32(intf.l3a_mac_addr, sa_fa->param);
    }

    if (NULL != vid_fa) {
        intf.l3a_vid = vid_fa->param[0];
    }

    if (SOC_IS_TRIUMPH2(unit) || SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit) ||
        SOC_IS_APOLLO(unit) || SOC_IS_ENDURO(unit)) {
        /* Create egress l3 interface. */
        BCM_IF_ERROR_RETURN(_bcm_xgs3_egress_l3_intf_id_alloc(unit,
            &intf.l3a_intf_id));

        /* Write egress interface to the hw. */
        sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));

        /* Set mac address. */
        soc_mem_mac_addr_set(unit, EGR_L3_INTFm, hw_buf,
            MAC_ADDRESSf, intf.l3a_mac_addr);

        /* Set vlan id. */
        soc_mem_field32_set(unit, EGR_L3_INTFm, hw_buf, VIDf, intf.l3a_vid);

        /* Write interface configuration to the HW. */
        rv = soc_mem_write(unit, EGR_L3_INTFm, SOC_BLOCK_ALL,
                intf.l3a_intf_id, hw_buf);
        if (BCM_FAILURE(rv)) {
            tmp_rv = _bcm_xgs3_egress_l3_intf_id_free(unit, intf.l3a_intf_id);
            return rv;
        }

        /* Allocate next hop entry. */
        nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
        rv = bcm_xgs3_nh_add(unit, nh_flags, &egr, &nh_index);
        if (BCM_FAILURE(rv)) {
            sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
            tmp_rv = soc_mem_write(unit, EGR_L3_INTFm, SOC_BLOCK_ALL,
                        intf.l3a_intf_id, hw_buf);
            tmp_rv = _bcm_xgs3_egress_l3_intf_id_free(unit, intf.l3a_intf_id);
            return (rv);
        }

        /* Write egress next hop entry. */
        sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
#ifdef BCM_TRIDENT_SUPPORT
        if (SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) {
            /* Set next hop entry type to IFP_ACTIONS. */
            soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                ENTRY_TYPEf, 6);

            /* Set next hop mac address. */
            soc_mem_mac_addr_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                IFP_ACTIONS__MAC_ADDRESSf, egr.mac_addr);

            /* Set interface id. */
            soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                IFP_ACTIONS__INTF_NUMf, intf.l3a_intf_id);

            /* Set Disable flags. */
            soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                IFP_ACTIONS__L3_UC_TTL_DISABLEf, 0x1);

            if (NULL == vid_fa) {
                soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                    IFP_ACTIONS__L3_UC_VLAN_DISABLEf, 0x1);
            }

            if (NULL == sa_fa) {
                soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                    IFP_ACTIONS__L3_UC_SA_DISABLEf, 0x1);
            }

            if (NULL == da_fa) {
                soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                    IFP_ACTIONS__L3_UC_DA_DISABLEf, 0x1);
            }

            if (NULL != vn_new_fa) {
                soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                    IFP_ACTIONS__VNTAG_ACTIONf, 0x1);
                soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                    IFP_ACTIONS__VNTAGf, vn_new_fa->param[0]);
            }

            if (NULL != vn_del_fa) {
                soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                    IFP_ACTIONS__VNTAG_ACTIONf, 0x3);
            }

        } else
#endif /* BCM_TRIDENT_SUPPORT */
        {
            /* Set next hop mac address. */
            soc_mem_mac_addr_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                MAC_ADDRESSf, egr.mac_addr);
    
            /* Set interface id. */
            soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                INTF_NUMf, intf.l3a_intf_id);

            /* Set Disable flags. */
            soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                L3__L3_UC_TTL_DISABLEf, 0x1);

            if (NULL == vid_fa) {
                soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                    L3__L3_UC_VLAN_DISABLEf, 0x1);
            }

            if (NULL == sa_fa) {
                soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                    L3__L3_UC_SA_DISABLEf, 0x1);
            }

            if (NULL == da_fa) {
                soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                    L3__L3_UC_DA_DISABLEf, 0x1);
            }
        }
        /* Insert next hop information. */
        rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm, SOC_BLOCK_ALL,
                nh_index, hw_buf);
        if (BCM_FAILURE(rv)) {
            sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
            tmp_rv = soc_mem_write(unit, EGR_L3_INTFm, SOC_BLOCK_ALL,
                        intf.l3a_intf_id, hw_buf);
            tmp_rv = _bcm_xgs3_egress_l3_intf_id_free(unit, intf.l3a_intf_id);
            return (rv);
        }
    } else {
        if (NULL != sa_fa) {
            /* Create egress l3 interface. */
            BCM_IF_ERROR_RETURN(_bcm_xgs3_egress_l3_intf_id_alloc(unit,
                &intf.l3a_intf_id));

            /* Write egress interface to the hw. */
            sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));

            /* Set mac address. */
            soc_mem_mac_addr_set(unit, EGR_L3_INTFm, hw_buf,
                MAC_ADDRESSf, intf.l3a_mac_addr);

            /* Set vlan id. */
            soc_mem_field32_set(unit, EGR_L3_INTFm, hw_buf, VIDf, intf.l3a_vid);

            /* Write interface configuration to the HW. */
            rv = soc_mem_write(unit, EGR_L3_INTFm, SOC_BLOCK_ALL,
                    intf.l3a_intf_id, hw_buf);
            if (BCM_FAILURE(rv)) {
                tmp_rv = _bcm_xgs3_egress_l3_intf_id_free(unit, intf.l3a_intf_id);
                return rv;
            }
        }

        /* Allocate next hop entry. */
        nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
        rv = bcm_xgs3_nh_add(unit, nh_flags, &egr, &nh_index);
        if (BCM_FAILURE(rv)) {
            if (NULL != sa_fa) {
                sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
                tmp_rv = soc_mem_write(unit, EGR_L3_INTFm, SOC_BLOCK_ALL,
                            intf.l3a_intf_id, hw_buf);
                tmp_rv = _bcm_xgs3_egress_l3_intf_id_free(unit, intf.l3a_intf_id);
            }
            return (rv);
        }

        /* Write egress next hop entry. */
        sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));

        /* Set next hop mac address. */
        soc_mem_mac_addr_set(unit, EGR_L3_NEXT_HOPm, hw_buf, MAC_ADDRESSf,
            egr.mac_addr);
    
        /* Set Outer Vlan ID. */
        if (NULL != vid_fa) {
            soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                INTF_NUMf, intf.l3a_vid);
        } else if (NULL != sa_fa) {
            /* Set interface id. */
            soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                INTF_NUMf, intf.l3a_intf_id);
        } else {
            /* Set interface id. */
            soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, hw_buf,
                INTF_NUMf, 0);
        }
        
        /* Insert next hop information. */
        rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm, SOC_BLOCK_ALL, 
                nh_index, hw_buf);
        if (BCM_FAILURE(rv)) {
            if (NULL != sa_fa) {
                sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
                tmp_rv = soc_mem_write(unit, EGR_L3_INTFm, SOC_BLOCK_ALL,
                            intf.l3a_intf_id, hw_buf);
                tmp_rv = _bcm_xgs3_egress_l3_intf_id_free(unit, intf.l3a_intf_id);
            }
            return (rv);
        }
    }

    /* Preserve next hop index in the action structure. */
    if (NULL != vid_fa) {
        vid_fa->hw_index = nh_index;
    }

    if (NULL != sa_fa) {
        sa_fa->hw_index = nh_index;
    }

    if (NULL != da_fa) {
        da_fa->hw_index = nh_index;
    }

    if (NULL != vn_new_fa) {
        da_fa->hw_index = nh_index;
    }

    if (NULL != vn_del_fa) {
        da_fa->hw_index = nh_index;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_l2_actions_hw_alloc
 *
 * Purpose:
 *     Allocate l3 next hop and egress interface for
 *     l2 fields update action.
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry descriptor.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_bcm_field_l2_actions_hw_alloc(int unit, _field_entry_t *f_ent)
{
    _field_action_t *vid_fa;        /* Update outer vid action.      */
    _field_action_t *sa_fa;         /* Update source mac action.     */
    _field_action_t *da_fa;         /* Update destination mac action.*/
    _field_action_t *vn_new_fa;     /* Change VN tag.                */
    _field_action_t *vn_del_fa;     /* Delete VN tag action.         */
    _field_action_t *fa;            /* Field action descriptor.      */

    /* Applicable to stage ingress on TRX devices only. */
    if ((0 == SOC_IS_TRX(unit) && 0 == SOC_IS_FB(unit)) ||
        (_BCM_FIELD_STAGE_INGRESS != f_ent->group->stage_id)) {
        return (BCM_E_NONE);
    }

    /* Initialization. */
    sa_fa = da_fa = vid_fa = vn_new_fa = vn_del_fa = NULL;

    /* Extract the policy info from the entry structure. */
    for (fa = f_ent->actions; fa != NULL; fa = fa->next) {
        switch (fa->action) {
          case bcmFieldActionSrcMacNew:
              if (_FP_INVALID_INDEX != fa->hw_index) {
                  fa->old_index = fa->hw_index;
              }
              sa_fa = fa;
              break;
          case bcmFieldActionDstMacNew:
              if (_FP_INVALID_INDEX != fa->hw_index) {
                  fa->old_index = fa->hw_index;
              }
              da_fa = fa;
              break;
          case bcmFieldActionOuterVlanNew:
              if (_FP_INVALID_INDEX != fa->hw_index) {
                  fa->old_index = fa->hw_index;
              }
              vid_fa = fa;
              break;
          case bcmFieldActionVnTagNew:
              if (_FP_INVALID_INDEX != fa->hw_index) {
                  fa->old_index = fa->hw_index;
              }
              vn_new_fa = fa;
              break;
          case bcmFieldActionVnTagDelete:
              if (_FP_INVALID_INDEX != fa->hw_index) {
                  fa->old_index = fa->hw_index;
              }
              vn_del_fa = fa;
              break;
          default:
              continue;
        }
    }

    /* Create nh entry. */
    if ((NULL != vid_fa) || (NULL != da_fa) || (NULL != sa_fa) ||
        (NULL != vn_new_fa) || (NULL != vn_del_fa)) {
        BCM_IF_ERROR_RETURN(_bcm_field_l2_actions_nh_create(unit, da_fa, sa_fa,
            vid_fa, vn_new_fa, vn_del_fa));
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_l2_actions_hw_free
 *
 * Purpose:
 *     Free l3 next hop and egress interface for
 *     l2 fields update action.
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry descriptor.
 *     flags     - (IN) Free flags (old/new/both).
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_bcm_field_l2_actions_hw_free(int unit, _field_entry_t *f_ent,
                                  uint32 flags)
{
    _field_action_t *fa;            /* Field action descriptor.      */
    int nh_index;                   /* Next hop index.               */
    int old_nh_index;               /* Old next hop index.           */
    int egr_intf_set = 0;            /* Egress interface allocated    */
    int rv = BCM_E_NONE;            /* Operation return status.      */

    /* Applicable to stage ingress on TRX devices only. */
    if ((0 == SOC_IS_TRX(unit) && 0 == SOC_IS_FB(unit)) ||
        (_BCM_FIELD_STAGE_INGRESS != f_ent->group->stage_id)) {
        return (BCM_E_NONE);
    }

    /* Initialization. */
    nh_index = old_nh_index = _FP_INVALID_INDEX;

    /* Extract the policy info from the entry structure. */
    for (fa = f_ent->actions; fa != NULL; fa = fa->next) {
        switch (fa->action) {
          case bcmFieldActionSrcMacNew:
              egr_intf_set = TRUE;
              /* passthru */
              /* coverity[MISSING_BREAK: FALSE] */
          case bcmFieldActionOuterVlanNew:
          case bcmFieldActionDstMacNew:
          case bcmFieldActionVnTagNew:
          case bcmFieldActionVnTagDelete:
              if ((flags & _FP_ACTION_RESOURCE_FREE) &&
                  (_FP_INVALID_INDEX != fa->hw_index)) {
                  nh_index = fa->hw_index;
                  fa->hw_index = _FP_INVALID_INDEX;
              }
              if ((flags & _FP_ACTION_OLD_RESOURCE_FREE) &&
                  (_FP_INVALID_INDEX != fa->old_index)) {
                  old_nh_index = fa->old_index;
                  fa->old_index = _FP_INVALID_INDEX;
              }
              break;
          default:
              break;
        }
    }

    /* Destroy old next hop if any. */
    if (_FP_INVALID_INDEX != old_nh_index) {
        rv = _bcm_field_l2_actions_nh_destroy(unit, old_nh_index, egr_intf_set);
        BCM_IF_ERROR_RETURN(rv);
    }
    if (_FP_INVALID_INDEX != nh_index) {
        rv = _bcm_field_l2_actions_nh_destroy(unit, nh_index, egr_intf_set);
        BCM_IF_ERROR_RETURN(rv);
    }
    return (BCM_E_NONE);
}
#endif /* INCLUDE_L3 */

/*
 * Function:
 *     _field_dest_type_clear
 * Purpose:
 *     Clear Destination Type value in qualifier data.
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     entry    - (IN) entry identifier.
 *     qual     - (IN) field qualifier.
 *     data     - (IN) qualifier data.
 *     mask     - (IN) qualifier mask.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_dest_type_clear(int unit, bcm_field_entry_t entry,
        bcm_field_qualify_t qual, uint32 *data, uint32 *mask)
{
#ifdef BCM_TRIUMPH2_SUPPORT
    _field_group_t *fg;         /* Field group structure              */
    int entry_width;            /* Forward Entity Select status       */
    int dst_fwd_entity_status;  /* dst_fwd_entity_sel selector status */
    
    /* Check if this device supports per-slice control fields */
    if (0 == soc_feature(unit, soc_feature_field_slice_dest_entity_select)) {
        return (BCM_E_NONE);
    }

    BCM_IF_ERROR_RETURN(_bcm_field_entry_group_find(unit, entry, &fg));
    /* 
     * Check if dst_fwd_entity_sel secondary selector is used.
     */
    for (entry_width = 0; entry_width < _FP_MAX_ENTRY_WIDTH; entry_width++) {
        switch (fg->sel_codes[entry_width].dst_fwd_entity_sel) {
            case _bcmFieldFwdEntityGlp:
                if (qual == bcmFieldQualifyDstPort
                    || qual == bcmFieldQualifyDstTrunk
                    || qual == bcmFieldQualifyDstModid) {
                    dst_fwd_entity_status = TRUE;
                } else {
                    dst_fwd_entity_status = FALSE;
                }
                break;
            case _bcmFieldFwdEntityMplsGport:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstMplsGport) ? TRUE: FALSE;
                break;
            case _bcmFieldFwdEntityMimGport:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstMimGport) ? TRUE: FALSE;
                break;
            case _bcmFieldFwdEntityWlanGport:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstWlanGport) ? TRUE: FALSE;
                break;
            case _bcmFieldFwdEntityL3Egress:
                dst_fwd_entity_status
                    = (qual == bcmFieldQualifyDstL3Egress)
                        ? TRUE : (qual == bcmFieldQualifyDstL3EgressNextHops)
                        ? TRUE : FALSE;
                break;
            case _bcmFieldFwdEntityMulticastGroup:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstMulticastGroup) ? TRUE: FALSE;
                break;
            case _bcmFieldFwdEntityMultipath:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstMultipath) ? TRUE: FALSE;
                break;
            default:
                dst_fwd_entity_status = FALSE;
        }
        if (TRUE == dst_fwd_entity_status) {
            break;
        }
    }   

    if (FALSE == dst_fwd_entity_status) {
        return BCM_E_NONE;
    } else {
        if (qual == bcmFieldQualifyDstModid) {
            _FIELD_D_TYPE_RESET_BITPOS(*data,
                _shr_popcount((unsigned int)SOC_MODID_MAX(unit)));
            _FIELD_D_TYPE_RESET_BITPOS(*mask,
                _shr_popcount((unsigned int)SOC_MODID_MAX(unit)));
        } else {
            _FIELD_D_TYPE_RESET(*data);
            _FIELD_D_TYPE_RESET(*mask);
        }
    }
#endif /* !BCM_TRIUMPH2_SUPPORT */
    return BCM_E_NONE;
}

/*
 * Function:
 *     _field_dest_type_qualify
 * Purpose:
 *     Set Destination Type value in qualifier data.
 * Parameters:
 *     unit             - (IN) BCM device number.
 *     entry            - (IN) entry identifier.
 *     qual             - (IN) field qualifier.
 *     data             - (IN) qualifier data.
 *     mask             - (IN) qualifier mask.
 *     ipmc_grp_type    - (IN) Multicast group type.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_dest_type_qualify(int unit, bcm_field_entry_t entry,
        bcm_field_qualify_t qual, uint32 *data, uint32 *mask,
        uint8 ipmc_grp_type)
{
#ifdef BCM_TRIUMPH2_SUPPORT
    _field_group_t *fg;         /* Field group structure              */
    int entry_width;            /* Forward Entity Select status       */
    int dst_fwd_entity_status;  /* dst_fwd_entity_sel selector status */

    /* Check if this device supports per-slice control fields */
    if (0 == soc_feature(unit, soc_feature_field_slice_dest_entity_select)) {
        return (BCM_E_NONE);
    }

    BCM_IF_ERROR_RETURN(_bcm_field_entry_group_find(unit, entry, &fg));
    /* 
     * Check if dst_fwd_entity_sel secondary selector is used.
     */
    for (entry_width = 0; entry_width < _FP_MAX_ENTRY_WIDTH; entry_width++) {
        switch (fg->sel_codes[entry_width].dst_fwd_entity_sel) {
            case _bcmFieldFwdEntityGlp:
                if (qual == bcmFieldQualifyDstPort
                    || qual == bcmFieldQualifyDstTrunk
                    || qual == bcmFieldQualifyDstModid) {
                    dst_fwd_entity_status = TRUE;
                } else {
                    dst_fwd_entity_status = FALSE;
                }
                break;
            case _bcmFieldFwdEntityMplsGport:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstMplsGport) ? TRUE: FALSE;
                break;
            case _bcmFieldFwdEntityMimGport:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstMimGport) ? TRUE: FALSE;
                break;
            case _bcmFieldFwdEntityWlanGport:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstWlanGport) ? TRUE: FALSE;
                break;
            case _bcmFieldFwdEntityL3Egress:
                dst_fwd_entity_status
                    = (qual == bcmFieldQualifyDstL3Egress)
                        ? TRUE : (qual == bcmFieldQualifyDstL3EgressNextHops)
                        ? TRUE : FALSE;
                break;
            case _bcmFieldFwdEntityMulticastGroup:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstMulticastGroup) ? TRUE: FALSE;
                break;
            case _bcmFieldFwdEntityMultipath:
                dst_fwd_entity_status =
                    (qual == bcmFieldQualifyDstMultipath) ? TRUE: FALSE;
                break;
            default:
                dst_fwd_entity_status = FALSE;
        }
        if (TRUE == dst_fwd_entity_status) {
            break;
        }
    }

    if (FALSE == dst_fwd_entity_status) {
        return BCM_E_NONE;
    } else {
        switch (qual) {
            case bcmFieldQualifyDstMplsGport:
            case bcmFieldQualifyDstMimGport:
            case bcmFieldQualifyDstWlanGport:
                _FIELD_D_TYPE_INSERT(*data, _bcmFieldDestTypeDvp);
                break;
            case bcmFieldQualifyDstL3Egress:
            case bcmFieldQualifyDstL3EgressNextHops:
                _FIELD_D_TYPE_INSERT(*data, _bcmFieldDestTypeNhi);
                break;
            case bcmFieldQualifyDstMultipath:
                _FIELD_D_TYPE_INSERT(*data, _bcmFieldDestTypeEcmp);
                break;
            case bcmFieldQualifyDstMulticastGroup:
                if (1 == ipmc_grp_type) {
                    _FIELD_D_TYPE_INSERT(*data, _bcmFieldDestTypeL3mc);
                } else {
                    _FIELD_D_TYPE_INSERT(*data, _bcmFieldDestTypeL2mc);
                }
                break;
            default:
                if (qual == bcmFieldQualifyDstModid) {
                    _FIELD_D_TYPE_INSERT_BITPOS(*data, _bcmFieldDestTypeDglp, 
                        _shr_popcount((unsigned int)SOC_MODID_MAX(unit)));
                } else {
                    _FIELD_D_TYPE_INSERT(*data, _bcmFieldDestTypeDglp);
                }
        }
    }

    if ((bcmFieldQualifyDstL3EgressNextHops == qual)
        || (bcmFieldQualifyDstTrunk == qual)) {
        _FIELD_D_TYPE_MASK_INSERT(*mask);
    } else {
        *mask = (BCM_FIELD_EXACT_MATCH_MASK);
    }
#endif /* !BCM_TRIUMPH2_SUPPORT */
    return BCM_E_NONE;
}

/*
 * Function:
 *     _bcm_field_qual_conf_t_init
 * Purpose:
 *     Initialize qualifier configuration structure.       
 * Parameters:
 *     ptr  - (OUT) Pointer to field qualifier configuration strucutre.
 *
 * Returns:
 *     Void.
 */
void
_bcm_field_qual_conf_t_init(_bcm_field_qual_conf_t *ptr)
{
    _bcm_field_selector_t  *selector;

    if (NULL == ptr) {
        return;
    }

    /* Reset qualifier configuration structure. */
    sal_memset(ptr, 0, sizeof(_bcm_field_qual_conf_t));

    /* Set Selectors to Don't care. */
    selector           = &ptr->selector;
    selector->dev_sel  = _bcmFieldDevSelDisable;
    selector->pri_sel  = _bcmFieldSliceSelDisable;
    selector->sec_sel  = _bcmFieldSliceSelDisable;

    return;
}

/*
 * Function:
 *     _bcm_field_qual_info_t_init
 * Purpose:
 *     Initialize qualifier info structure.       
 * Parameters:
 *     ptr  - (OUT) Pointer to field qualifier info strucutre.
 *
 * Returns:
 *     Void.
 */
void
_bcm_field_qual_info_t_init(_bcm_field_qual_info_t *ptr)
{
    /* Input parameters check. */
    if (NULL == ptr) {
        return;
    }

    /* Reset qualifier configuration structure. */
    sal_memset(ptr, 0, sizeof(_bcm_field_qual_info_t));

    return;
}

/*
 * Function:
 *     _bcm_field_qual_insert
 * Purpose:
 *     Add qualifier to stage qualifers list. 
 * Parameters:
 *     unit     - (IN) BCM device number.  
 *     stage_fc - (IN) Stage field control strucutre.
 *     f_qual   - (IN) FP qualifier info. 
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_qual_insert (int unit, _field_stage_t *stage_fc, 
                        int qual_id, _bcm_field_qual_conf_t *ptr)
{
    _bcm_field_qual_info_t *f_qual = NULL;         /* Field qualifier info.       */
    _bcm_field_qual_conf_t *f_qual_conf = NULL;    /* Qualifier configuration.    */
    _bcm_field_qual_conf_t *f_qual_conf_old = NULL;/* Old Qualifier configuration.*/
    int alloc_size;                                /* Memory allocation size.     */

    /* Input parameters check. */
    if ((NULL == ptr) || (NULL == stage_fc) || 
        (qual_id < 0) || (qual_id > _bcmFieldQualifyCount)) {
        return BCM_E_PARAM;
    }

    f_qual = stage_fc->f_qual_arr[qual_id];
    /* Allocate qualifier descriptor. */
    if (NULL == f_qual) {
        alloc_size = sizeof(_bcm_field_qual_info_t);
        _FP_XGS3_ALLOC(f_qual, alloc_size, "FP qualifier info");
        if (NULL == f_qual) {
            return (BCM_E_MEMORY);
        }
        _bcm_field_qual_info_t_init(f_qual);
        f_qual->qid = qual_id;
    }

    /* Preserve original qualifier configurations array. */
    f_qual_conf_old = f_qual->conf_arr; 

    /* Allocate qualifier configurations array. */
    /* Re-alloc configuration array if qualifier has multiple configurations. */
    alloc_size = (f_qual->conf_sz + 1) * sizeof (_bcm_field_qual_conf_t);

    /* Allocated qualifier descriptor. */
    _FP_XGS3_ALLOC(f_qual_conf, alloc_size, "FP qualifier config");
    if (NULL == f_qual_conf) {
        sal_free(f_qual);
        stage_fc->f_qual_arr[qual_id] = NULL;
        return (BCM_E_MEMORY);
    }

    /* Copy previous configurations if any.  */
    if (NULL != f_qual->conf_arr) {
        alloc_size -= sizeof(_bcm_field_qual_conf_t);
        sal_memcpy (f_qual_conf, f_qual->conf_arr, alloc_size);
        sal_free(f_qual->conf_arr);
    }

    /* Set configuration array pointer to a new array. */ 
    f_qual->conf_arr = f_qual_conf;

    /* Copy new configuration to configuration array. */
    f_qual->conf_arr[f_qual->conf_sz] = *ptr;

    /* Increment number of active configurations. */
    f_qual->conf_sz++;

    /* Install qualifier into stage qualifiers array. */
    stage_fc->f_qual_arr[qual_id] = f_qual;

    return (BCM_E_NONE);
}


/*
 * Function:
 *      _field_selector_update_cmp
 * Purpose:
 *      Compare number of update required in order to use 
 *      a qualifier select code.
 * Parameters:
 *      b - (IN) first compared selector.
 *      a - (IN) second compared selector. 
 * Returns:
 *      a<=>b
 */
STATIC INLINE int
_field_selector_update_cmp(void *a, void *b)
{
    _bcm_field_qual_conf_t *first;     /* First compared selector.  */
    _bcm_field_qual_conf_t *second;    /* Second compared selector. */

    first = (_bcm_field_qual_conf_t *)a;
    second = (_bcm_field_qual_conf_t *)b;

    if (first->selector.update_count <  
        second->selector.update_count) {
        return (-1);
    } else if (first->selector.update_count > 
               second->selector.update_count) {
        return (1);
    }
    return (0);
}

/*
 * Function:
 *      _field_qual_info_cmp
 * Purpose:
 *      Compare frequency of two qualifiers appearance.
 * Parameters:
 *      b - (IN) first compared qualifier.
 *      a - (IN) second compared qualifier. 
 * Returns:
 *      a<=>b
 */
STATIC INLINE int
_field_qual_info_cmp (void *a, void *b)
{
    _bcm_field_qual_info_t **first;     /* First compared qualifier.  */
    _bcm_field_qual_info_t **second;    /* Second compared qualifier. */

    first = (_bcm_field_qual_info_t **)a;
    second = (_bcm_field_qual_info_t **)b;

    if ((*first)->conf_sz < (*second)->conf_sz) {
        return (-1);
    } else if ((*first)->conf_sz > (*second)->conf_sz) {
        return (1);
    }
    return (0);
}

/*
 * Function:
 *     _field_selector_insert
 * Purpose:
 *     Insert selector into a specific tcam part of the entry.
 * Parameters:
 *     sel_arr     - (IN) Current entry select codes.
 *     part_idx    - (IN) Tcam part index. 
 *     selector     - (IN) Inserted selector.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_selector_insert (_field_sel_t *sel_arr, int part_idx, 
                        _bcm_field_selector_t *selector)
{
    _field_sel_t *tcam_part;   /* Tcam part selectors. */

    /* Input parameters check. */
    if ((NULL == sel_arr) || (NULL == selector)) {
        return (BCM_E_PARAM);
    }

    tcam_part = sel_arr + part_idx;

    /* Per device selector. */
    switch (selector->dev_sel) {
      case _bcmFieldDevSelDisable:
          break;
      case _bcmFieldDevSelInnerVlanOverlay:
          sel_arr[0].inner_vlan_overlay = selector->dev_sel_val;
          break;
      case _bcmFieldDevSelIntrasliceVfpKey:
          sel_arr[0].intraslice_vfp_sel = selector->dev_sel_val;
          break;
      default:
          return (BCM_E_INTERNAL);
    }

    /* Primary slice selector. */
    switch (selector->pri_sel) {
      case _bcmFieldSliceSelDisable:
          break;
      case _bcmFieldSliceSelFpf1:
          tcam_part->fpf1 = selector->pri_sel_val;
          break;
      case _bcmFieldSliceSelFpf2:
          tcam_part->fpf2 = selector->pri_sel_val;
          break;
      case _bcmFieldSliceSelFpf3:
          tcam_part->fpf3 = selector->pri_sel_val;
          break;
      case _bcmFieldSliceSelFpf4:
          tcam_part->fpf4 = selector->pri_sel_val;
          break;
      case _bcmFieldSliceSelExternal:
          tcam_part->extn = selector->pri_sel_val;
          break;
      default:
          return (BCM_E_INTERNAL);
    }

    /* Per slice selectors are inserted into primary slice only. */
    if ((selector->intraslice) && (0 != part_idx)) {
        tcam_part = sel_arr + (part_idx - 1);
    }

    /* Secondary slice selector. */
    switch (selector->sec_sel) {
    case _bcmFieldSliceSelDisable:
        break;
    case _bcmFieldSliceSrcClassSelect:
        tcam_part->src_class_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceDstClassSelect:
        tcam_part->dst_class_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceIntfClassSelect:
        tcam_part->intf_class_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceLoopbackTypeSelect:
        tcam_part->loopback_type_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceIngressEntitySelect:
        tcam_part->ingress_entity_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceSrcEntitySelect:
        tcam_part->src_entity_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceDstFwdEntitySelect:
        tcam_part->dst_fwd_entity_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceFwdFieldSelect:
        tcam_part->fwd_field_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceIpHeaderSelect:
        tcam_part->ip_header_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceIp6AddrSelect:
        tcam_part->ip6_addr_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceAuxTag1Select:
        tcam_part->aux_tag_1_sel = selector->sec_sel_val;
        break;
    case _bcmFieldSliceAuxTag2Select:
        tcam_part->aux_tag_2_sel = selector->sec_sel_val;
        break;
    default:
        return (BCM_E_INTERNAL);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_selector_diff
 * Purpose:
 *     Compare selector configuration with current selectors 
 *     status of field group entry.  
 * Parameters:
 *     unit        - (IN) BCM device number.
 *     sel_arr     - (IN) Current entry select codes.
 *     part_idx    - (IN) Tcam part index. 
 *     selector    - (IN) Compared selector.
 *     diff_count  - (OUT) Number of different elements.  
 * Returns:
 *     BCM_E_XXX
 * NOTE: 
 *     Function returns BCM_E_RESOURCE if configurations are conflicting.
 */
int
_field_selector_diff(int unit, _field_sel_t *sel_arr, int part_idx, 
                     _bcm_field_selector_t *selector, 
                     uint8 *diff_count)
{
    uint8 count;                   /* Required updates count. */
    _field_sel_t *tcam_part;       /* Tcam part selectors.    */
#if defined(BCM_FIREBOLT_SUPPORT)
    int temp;                      /* Temporary test variable.*/
    int rv;                        /* Operation return status.*/
#endif /* BCM_FIREBOLT_SUPPORT */

    /* Input parameters check. */
    if ((NULL == sel_arr) || (NULL == selector) || (NULL == diff_count)) {
        return (BCM_E_PARAM);
    }

    count = 0;
    tcam_part = sel_arr + part_idx;

    /* Qualifier is available in the second part of intraslice entry */
    if (selector->intraslice) {
        if (_FP_SELCODE_DONT_USE == tcam_part->intraslice) {
            return (BCM_E_RESOURCE);
        }
    } else {
        if (_FP_SELCODE_DONT_USE != tcam_part->intraslice) {
            return (BCM_E_RESOURCE);
        }
    }

    /* Qualifier is available only in the secondary part of a paired
       entry */

    if (selector->secondary) {
        if (_FP_SELCODE_DONT_USE == tcam_part->secondary) {
            return (BCM_E_RESOURCE);
        }
    }

    /* Per device selectors. */
    switch (selector->dev_sel) {
      case _bcmFieldDevSelDisable:
          break;
#if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_RAVEN_SUPPORT)
      case _bcmFieldDevSelInnerVlanOverlay:
          rv = _bcm_field_fb_group_inner_vlan_overlay_get(unit, &temp);
          BCM_IF_ERROR_RETURN(rv);
          if (((_FP_SELCODE_DONT_CARE != temp)  && 
               (temp != selector->dev_sel_val)) ||
              ((_FP_SELCODE_DONT_CARE != sel_arr[0].inner_vlan_overlay) && 
               (sel_arr[0].inner_vlan_overlay != selector->dev_sel_val))) {
              return (BCM_E_RESOURCE);
          }
          break;
#endif /* BCM_FIREBOLT_SUPPORT */
#if defined(BCM_FIREBOLT2_SUPPORT)           
      case _bcmFieldDevSelIntrasliceVfpKey:
          rv = _bcm_field_vfp_doublewide_key_select_get(unit, &temp);
          BCM_IF_ERROR_RETURN(rv);
          if (((_FP_SELCODE_DONT_CARE != temp)  && 
               (temp != selector->dev_sel_val)) ||
              ((_FP_SELCODE_DONT_CARE != sel_arr[0].intraslice_vfp_sel) && 
               (sel_arr[0].intraslice_vfp_sel != selector->dev_sel_val))) {
              return (BCM_E_RESOURCE);
          }
          break;
#endif /* BCM_FIREBOLT2_SUPPORT */
      default:
          return (BCM_E_INTERNAL);
    }


    /* Primary slice selector. */
    switch (selector->pri_sel) {
      case _bcmFieldSliceSelDisable:
          break;
      case _bcmFieldSliceSelFpf1:
          if (tcam_part->fpf1 == _FP_SELCODE_DONT_CARE) {  
              count++;
          } else if (tcam_part->fpf1 != selector->pri_sel_val) { 
              return (BCM_E_RESOURCE);
          }
          break;
      case _bcmFieldSliceSelFpf2:
          if (tcam_part->fpf2 == _FP_SELCODE_DONT_CARE) {  
              count++;
          } else if (tcam_part->fpf2 != selector->pri_sel_val) {
              return (BCM_E_RESOURCE);
          }
          break;
      case _bcmFieldSliceSelFpf3:
          if (tcam_part->fpf3 == _FP_SELCODE_DONT_CARE) {  
              count++;
          } else if (tcam_part->fpf3 != selector->pri_sel_val) {
              return (BCM_E_RESOURCE);
          }
          break;
      case _bcmFieldSliceSelFpf4:
          if (tcam_part->fpf4 == _FP_SELCODE_DONT_CARE) {  
              count++;
          } else if (tcam_part->fpf4 != selector->pri_sel_val) {
              return (BCM_E_RESOURCE);
          }
          break;
      case _bcmFieldSliceSelExternal:
          if (tcam_part->extn == _FP_SELCODE_DONT_CARE) {  
              count++;
          } else if (tcam_part->extn != selector->pri_sel_val) {
              return (BCM_E_RESOURCE);
          }
          break;
      default:
          return (BCM_E_INTERNAL);
    }

    /* Secondary slice selector. */
    /* Per slice selectors are inserted into primary slice only. */
    if ((selector->intraslice) && (0 != part_idx)) {
        tcam_part = sel_arr + (part_idx - 1);
    }

    switch (selector->sec_sel) {
    case _bcmFieldSliceSelDisable:
        break;
    case _bcmFieldSliceSrcClassSelect:
        if (tcam_part->src_class_sel == _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->src_class_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceDstClassSelect:
        if (tcam_part->dst_class_sel == _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->dst_class_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceIntfClassSelect:
        if (tcam_part->intf_class_sel == _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->intf_class_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceLoopbackTypeSelect:
        if (tcam_part->loopback_type_sel == _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->loopback_type_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceIngressEntitySelect:
        if (tcam_part->ingress_entity_sel == _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->ingress_entity_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceSrcEntitySelect:
        if (tcam_part->src_entity_sel == _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->src_entity_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceDstFwdEntitySelect:
        if (tcam_part->dst_fwd_entity_sel == _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->dst_fwd_entity_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceFwdFieldSelect:
        if (tcam_part->fwd_field_sel == _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->fwd_field_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceIpHeaderSelect:
        if (tcam_part->ip_header_sel== _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->ip_header_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceIp6AddrSelect:
        if (tcam_part->ip6_addr_sel == _FP_SELCODE_DONT_CARE) {  
            count++;
        } else if (tcam_part->ip6_addr_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceAuxTag1Select:
        if (tcam_part->aux_tag_1_sel == _FP_SELCODE_DONT_CARE) {
            ++count;
        } else if (tcam_part->aux_tag_1_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    case _bcmFieldSliceAuxTag2Select:
        if (tcam_part->aux_tag_2_sel == _FP_SELCODE_DONT_CARE) {
            ++count;
        } else if (tcam_part->aux_tag_2_sel != selector->sec_sel_val) {
            return (BCM_E_RESOURCE);
        }
        break;
    default:
        return (BCM_E_INTERNAL);
    }
    *diff_count = count;
    return (BCM_E_NONE);
}

/* Compare 2 selector structures, accounting for don't cares.
   Returns 0 if equal, 1 if not.
*/

int
_field_sel_cmp(_field_sel_t *sel1, _field_sel_t *sel2)
{
#define SELCMP(f)                                     \
    if (sel1->f != _FP_SELCODE_DONT_CARE              \
        && sel2->f != _FP_SELCODE_DONT_CARE           \
        && sel1->f != sel2->fpf0                      \
        ) {                                           \
        return (1);                                   \
    }

    SELCMP(fpf0);
    SELCMP(fpf1);
    SELCMP(fpf2);
    SELCMP(fpf3);
    SELCMP(fpf4);
    SELCMP(extn);
    SELCMP(src_class_sel);
    SELCMP(dst_class_sel);
    SELCMP(intf_class_sel);
    SELCMP(ingress_entity_sel);
    SELCMP(src_entity_sel);
    SELCMP(dst_fwd_entity_sel);
    SELCMP(fwd_field_sel);
    SELCMP(loopback_type_sel);
    SELCMP(ip_header_sel);
    SELCMP(ip6_addr_sel);
    SELCMP(intraslice);
    SELCMP(secondary);
    SELCMP(inner_vlan_overlay);
    SELCMP(intraslice_vfp_sel);

    return (0);
}


/*
 * Function:
 *     _field_slice_is_empty
 * 
 * Purpose:
 *     Report if a slice has any entries.
 *
 * Parameters:
 *     fc     - (IN) Field control structure. 
 *     fs     - (IN) Slice control structure. 
 *     empty - (OUT) True - slice is empty/False otherwise.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_slice_is_empty(int unit, _field_slice_t *fs, uint8 *empty)
{
    int ratio = 1;                  /* Free to Total entry ratio.     */

    /* Input parameters check. */
    if (NULL == fs) {
        return (BCM_E_PARAM); 
    }

    if (fs->group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
        ratio = 2;
    }

    if (fs->entry_count == ratio * fs->free_count) {
        *empty = TRUE;
    } else {
        *empty = FALSE;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_group_status_init
 * Purpose:
 *     Initialize bcm_field_group_status_t structure.
 * Parameters:
 *     unit  -  (IN)BCM unit number.
 *     entry -  (OUT)Initialized field group status structure.   
 * Retruns: 
 *     BCM_E_XXX   
 */
int
_bcm_field_group_status_init(int unit, bcm_field_group_status_t *entry)
{
    /* Input parameters check. */
    if (NULL == entry) {
        return (BCM_E_PARAM);
    }

    sal_memset(entry, 0,  sizeof(bcm_field_group_status_t));

    entry->prio_min = 0;
    entry->prio_max = BCM_FIELD_ENTRY_PRIO_HIGHEST;
    entry->entries_total = -1;
    entry->entries_free = -1;
    entry->counters_total = -1;
    entry->counters_free = -1;
    entry->meters_total = -1;
    entry->meters_free = -1;
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_stage_entries_free
 * Purpose:
 *     Free entries array for all stage slices.
 * Parameters:
 *     unit     -  (IN)BCM unit number.
 *     stage_fc -  (IN)Stage field control
 * Retruns: 
 *     BCM_E_XXX   
 */
int
_bcm_field_stage_entries_free(int unit, _field_stage_t *stage_fc)
{
    _field_slice_t *fs;   /* Field slice pointer.   */
    int idx;              /* Slice iteration index. */

    /* Input parameters check */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }
    /* Deallocate the entry pointers */
    for (idx = 0; idx < stage_fc->tcam_slices; idx++) {
        fs = stage_fc->slices + idx;
        if (NULL != fs->entries) {
            sal_free(fs->entries);
            fs->entries = NULL;
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_control_get
 * Purpose:
 *     Lookup a FP control config from a bcm device id.
 * Parameters:
 *     unit -  (IN)BCM unit number.
 *     fc   -  (OUT) Field control structure.   
 * Retruns: 
 *     BCM_E_XXX   
 */
int
_field_control_get(int unit, _field_control_t **fc)
{
    /* Input parameters check. */
    if (NULL == fc) {
        return (BCM_E_PARAM);
    }

    /* Make sure system was initialized. */
    FIELD_IS_INIT(unit);

    /* Fill field control structure. */
    *fc = _field_control[unit];

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stage_control_get
 * Purpose:
 *     Lookup stage FP control config from bcm device id and 
 *     pipeline stage number.
 * Parameters:
 *     unit      -  (IN)BCM unit number.
 *     stage_id  -  (IN)Pipeline stage id number. 
 *     stage_fc  -  (OUT) Stage Field control structure.   
 * Retruns: 
 *     BCM_E_XXX   
 */
int
_field_stage_control_get(int unit, _field_stage_id_t stage_id,
                          _field_stage_t **stage_fc)
{
    _field_stage_t *stage_p;  /* Stages iteration pointer. */

    FIELD_IS_INIT(unit);                                      \

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    /* Check that module was initialized. */
    if (NULL == (_field_control[unit])->stages) {
        FP_ERR(("FP(unit %d) Error: Stage (%d) is not initialized.\n", 
                unit, stage_id));
        return (BCM_E_INIT);
    }

    /* Find a stage with stage_id equals to stage. */
    stage_p = (_field_control[unit])->stages;
    while (stage_p) {
        if (stage_p->stage_id == stage_id) {
            break;
        }
        stage_p = stage_p->next;
    }

    if (NULL == stage_p) {
        FP_ERR(("FP(unit %d) Error: Unknown pipeline stage (%d).\n",
                unit, stage_id));
        if (_BCM_FIELD_STAGE_EXTERNAL == stage_id) {
            return (BCM_E_UNAVAIL);
        } else {
            return (BCM_E_NOT_FOUND);
        }
    }

    /* Fill stage field control structure. */
    *stage_fc = stage_p;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_group_get
 * Purpose:
 *     Lookup a group information on specified bcm device.
 * Parameters:
 *     unit - (IN)BCM device number.
 *     gid  - (IN)Group ID.
 * Returns: 
 *     BCM_E_XXX 
 */
int
_field_group_get(int unit, bcm_field_group_t gid, _field_group_t **group_p)
{
    _field_control_t    *fc;          /* Unit FP control structure. */
    _field_group_t      *fg;          /* Group information.         */

    if (NULL == group_p) {
        return (BCM_E_PARAM);
    }

    /* Get unit FP control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Iterate over the groups linked-list looking for a matching Group ID */
    fg = fc->groups;
    while (fg != NULL) {
        if (fg->gid == gid) {
            *group_p = fg;
            return (BCM_E_NONE);
        }
        fg = fg->next;
    }
    /* Group with id == gid not found. */
    return (BCM_E_NOT_FOUND);
}

/* 
 * Function:
 *     _field_group_id_generate
 *
 * Purpose:
 *     Find an unused Group ID.
 *
 * Parameters:
 *     unit  - BCM device number
 *     group - (OUT) new Group ID
 *
 * Returns:
 *     BCM_E_NONE  - Success
 *     BCM_E_PARAM - null pointer to group
 */
int
_field_group_id_generate(int unit, bcm_field_group_t *group)
{
    _field_group_t *group_p;  /* Group info. */

    /* Input parameters check. */
    if (NULL == group) {
        FP_ERR(("FP(unit %d) Error: group == NULL\n", unit));
        return (BCM_E_PARAM);
    }

    *group = _FP_ID_BASE;

    while (!BCM_FAILURE(_field_group_get(unit, *group, &group_p))) {
        (*group)++;
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_entry_tcam_parts_count
 * Purpose:
 *     Get number of tcam entries needed to accomodate an entry.
 * Parameters:
 *     unit        - (IN)  BCM device number.
 *     group_flags - (IN)  Entry group flags.
 *     count       - (OUT) Entry parts count.
 * Returns:
 *     BCM_E_XXX 
 */
int
_bcm_field_entry_tcam_parts_count (int unit, uint32 group_flags, 
                                   int *part_count)
{
    /* Input parameters check. */
    if (NULL == part_count) {
        return (BCM_E_PARAM);
    }

    if (group_flags & _FP_GROUP_SPAN_SINGLE_SLICE) {
        if (group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            *part_count = 2;
        } else {
            *part_count = 1;
        }
    } else if (group_flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
        if (group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            *part_count = 4;
        } else {
            *part_count = 2;
        }
    } else if (group_flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
        *part_count = 3;
    }

    return BCM_E_NONE;
}

/*
 * Function:
 *     _field_entry_action_dirty
 * Purpose:
 *     Check if only action was modified for the entry after last installation
 * Parameters:
 *     unit        - (IN)  BCM device number.
 *     f_ent       - (IN)  Primary entry pointer.
 *     dirty       - (OUT) Entry dirty flag.
 * Returns:
 *     BCM_E_XXX 
 */
int
_field_entry_action_dirty(int unit, _field_entry_t *f_ent, int *dirty)
{
    int parts_count;                   /* Entry tcam parts count.       */
    int idx;                           /* Entry parts iterator.         */
    int rv;                            /* Operation return status.      */

    /* Input parameters check. */
    if ((NULL == f_ent) || (NULL == dirty)) {
        return (BCM_E_PARAM);
    }

    /* Get number of tcam parts based on group flags. */
    rv = _bcm_field_entry_tcam_parts_count (unit, f_ent->group->flags,
                                            &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Check entry dirty and action only dirty for all parts of the entry */
    for (idx = 0; idx < parts_count; idx++) {
        FP_VVERB(("FP(unit %d) vverb: _field_entry_action_dirty() Part:%x EntryDirty:%x ActionOnlyDirty:%x\n", 
            unit, idx, (f_ent[idx].flags & (_FP_ENTRY_DIRTY)), 
            (f_ent[idx].flags & (_FP_ENTRY_ACTION_ONLY_DIRTY))));
        /* 
         * If entry dirty is set and action only dirty is not set,
         * it is likely a qualifier change, return FALSE. 
         */ 
        if ((f_ent[idx].flags & _FP_ENTRY_DIRTY) && 
            (0 == (f_ent[idx].flags & _FP_ENTRY_ACTION_ONLY_DIRTY))) {
            *dirty = FALSE;
            return (BCM_E_NONE);
        }

        if ((f_ent[idx].flags & _FP_ENTRY_DIRTY) && 
            (f_ent[idx].flags & _FP_ENTRY_ACTION_ONLY_DIRTY)) {
            *dirty = TRUE;
        }
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_entry_dirty
 * Purpose:
 *     Check if entry was modified after last installation
 * Parameters:
 *     unit        - (IN)  BCM device number.
 *     f_ent       - (IN)  Primary entry pointer.
 *     dirty       - (OUT) Entry dirty flag.
 * Returns:
 *     BCM_E_XXX 
 */
int
_field_entry_dirty(int unit, _field_entry_t *f_ent, int *dirty)
{
    _field_entry_policer_t *f_ent_pl;  /* Field entry policer structure.*/
    _field_policer_t *f_pl;            /* Field policer descriptor.     */
    int parts_count;                   /* Entry tcam parts count.       */
    int idx;                           /* Entry parts iterator.         */
    int rv;                            /* Operation return status.      */

    /* Input parameters check. */
    if ((NULL == f_ent) || (NULL == dirty)) {
        return (BCM_E_PARAM);
    }

    /* Get number of tcam parts based on group flags. */
    rv = _bcm_field_entry_tcam_parts_count (unit, f_ent->group->flags,
                                            &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* If any entry part was changed - reinstall is required. */
    for (idx = 0; idx < parts_count; idx++) {
        if (f_ent[idx].flags & _FP_ENTRY_DIRTY) {
            break;
        }
    }
    *dirty = (idx < parts_count) ? TRUE : FALSE;

    if (0 == (*dirty)) {
        /* Policer configuration updates check. */
        for (idx = 0; idx < _FP_POLICER_LEVEL_COUNT; idx++) {
            f_ent_pl = f_ent->policer + idx;
            /* Skip invalid policers. */
            if (0 == (f_ent_pl->flags & _FP_POLICER_VALID)) {
                continue;
            }
            /* Read policer configuration.*/
            rv = _bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl);
            BCM_IF_ERROR_RETURN(rv);

            /* Check if policer was modified. */
            if (f_pl->hw_flags & _FP_POLICER_DIRTY) {
                *dirty = TRUE;
                break;
            }
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_entry_flags_to_tcam_part
 * Purpose:
 *     Each field entry contains up to 4 TCAM 
 *     entries. This routine maps sw entry flags
 *     to tcam entry (0-3). 
 *     Note this is not a physical address in tcam.
 *     Single: 0
 *     Single & Intraslice Double: 0, 1
 *     Paired: 0, 1
 *     Paired & Intraslice Double: 0, 1, 2, 3
 *     Triple: 0, 1, 2
 * Parameters:
 *     entry_flags - (IN)  Entry flags. 
 *     group_flags - (IN)  Entry group flags. 
 *     entry_part  - (OUT) Entry part (0-3)
 * Returns:
 *     BCM_E_NONE  - Success
 *     BCM_E_INTERNAL - Error
 */
int
_bcm_field_entry_flags_to_tcam_part (uint32 entry_flags, uint32 group_flags, 
                                     uint8 *entry_part)
{
    /* Input parameters check. */
    if (NULL == entry_part) {
        return (BCM_E_PARAM);
    }

    if (entry_flags & _FP_ENTRY_PRIMARY) {
        if (entry_flags & _FP_ENTRY_SECOND_HALF) {
            *entry_part = 1;
        } else {
            *entry_part = 0;
        }
    } else if (entry_flags & _FP_ENTRY_SECONDARY) {
        if (group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            if (entry_flags & _FP_ENTRY_SECOND_HALF) {
                *entry_part = 3;
            } else {
                *entry_part = 2;
            }
        } else {
            *entry_part= 1;
        }
    } else if (entry_flags & _FP_ENTRY_TERTIARY) {
        *entry_part = 2;
    } else {
        return (BCM_E_INTERNAL);
    }
    return BCM_E_NONE;
}

/*
 * Function:
 *     _bcm_field_tcam_part_to_entry_flags
 * Purpose:
 *     Each field entry contains up to 4 TCAM 
 *     entries. This routine maps tcam entry (0-3)
 *     to SW entry flags. 
 *     Single: 0
 *     Single & Intraslice Double: 0, 1
 *     Paired: 0, 1
 *     Paired & Intraslice Double: 0, 1, 2, 3
 *     Triple: 0, 1, 2
 *     Retrieve the part of the group entry resides in.
 * Parameters:
 *     entry_flags - (IN)  Entry flags. 
 *     group_flags - (IN)  Entry group flags. 
 *     entry_part  - (OUT) Entry part (0-3)
 * Returns:
 *     BCM_E_NONE  - Success
 *     BCM_E_INTERNAL - Error
 */
int
_bcm_field_tcam_part_to_entry_flags(int entry_part, uint32 group_flags, 
                                    uint16 *entry_flags)
{
    /* Input parameters check. */
    if (NULL == entry_flags) {
        return (BCM_E_PARAM);
    }

    switch (entry_part) {
      case 0:
          *entry_flags = _FP_ENTRY_PRIMARY;
          break;
      case 1: 
          if (group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
              *entry_flags = _FP_ENTRY_PRIMARY | _FP_ENTRY_SECOND_HALF;
          } else {
              *entry_flags = _FP_ENTRY_SECONDARY;
          }
          break;
      case 2:
          if (group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
              *entry_flags = _FP_ENTRY_SECONDARY;
          } else {
              *entry_flags = _FP_ENTRY_TERTIARY;
          }
          break; 
      case 3: 
          *entry_flags = _FP_ENTRY_SECONDARY | _FP_ENTRY_SECOND_HALF;
          break; 
      default: 
          return (BCM_E_INTERNAL);
    }
    return (BCM_E_NONE);
} 


/*
 * Function:
 *     _bcm_field_tcam_part_to_slice_number
 * Purpose:
 *     Each field entry contains up to 4 TCAM 
 *     entries. This routine maps tcam entry (0-3)
 *     to a slice number
 * Parameters:
 *     entry_flags  - (IN)  Entry flags. 
 *     group_flags  - (IN)  Entry group flags. 
 *     slice_number - (OUT) Slice number (0-2)
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_tcam_part_to_slice_number(int entry_part, 
                                     uint32 group_flags, 
                                     uint8 *slice_number)
{
    /* Input parameters check. */
    if (NULL == slice_number) {
        return (BCM_E_PARAM);
    }

    switch (entry_part) {
      case 0:
          *slice_number = 0;
          break;
      case 1:
          if (group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
              *slice_number = 0;
          } else {
              *slice_number = 1;
          }
          break;
      case 2:
          if (group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
              *slice_number = 1;
          } else {
              *slice_number = 2;
          }
          break;
      case 3:
          *slice_number = 1;
          break;
      default:
          return (BCM_E_INTERNAL);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_entry_slice_idx_change
 * Purpose:
 *     Move the software entry to a new slice index.
 * Parmeters:
 *     unit    - (IN) BCM device number. 
 *     f_ent   - (IN/OUT) Field entry to be moved.
 *     amount  - (IN) Number of indexes to move + or -.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int 
_field_entry_slice_idx_change(int unit, _field_entry_t *f_ent, 
                              int parts_count, int *tcam_idx_new)
{
    _field_slice_t *fs;          /* Field slice control structure. */ 
    _field_stage_t *stage_fc;    /* Stage field control structure. */
    int new_slice_numb = 0;      /* Entry new slice number.        */
    int new_slice_idx = 0;       /* Entry new offset in the slice  */ 
    int idx;                     /* Iteration index.               */
    int rv;                      /* Operation return status.       */

    /* Input parameters check. */                 
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    if ((NULL == f_ent->group) || (NULL == f_ent->fs)) { 
        return (BCM_E_PARAM);
    }

    /*  Get stage control structure. */
    rv = _field_stage_control_get(unit, f_ent->group->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    for (idx = 0; idx < parts_count; idx++) {
        /* Get slice control structure. */
        fs = f_ent[idx].fs;

        /* Move the software entry to the new index. */             
        if (prio_set_with_no_free_entries == FALSE) {
            fs->entries[f_ent[idx].slice_idx] = NULL;
        }

        /* Calculate entry new slice & offset in the slice. */
        rv = _bcm_field_tcam_idx_to_slice_offset (unit, stage_fc,
                                                  tcam_idx_new[idx],
                                                  &new_slice_numb,
                                                  &new_slice_idx);
        BCM_IF_ERROR_RETURN(rv);

        /* If entry moves across the slices update free/used counters. */
        if ((f_ent[idx].fs->slice_number != new_slice_numb) &&  
            (0 == (f_ent[idx].flags & _FP_ENTRY_SECOND_HALF))) {
            fs->free_count++;
            stage_fc->slices[new_slice_numb].free_count--;
        }

        /* Update entry structure. */
        stage_fc->slices[new_slice_numb].entries[new_slice_idx] = f_ent + idx;
        f_ent[idx].fs = &stage_fc->slices[new_slice_numb];
        f_ent[idx].slice_idx = new_slice_idx;
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_entry_t_compare
 * Purpose:
 *      Compare entry id in _field_entry_t structure.
 * Parameters:
 *      b - (IN) first compared qualifier.
 *      a - (IN) second compared qualifier. 
 * Returns:
 *      a<=>b
 */
STATIC INLINE int
_field_entry_t_compare(void *a, void *b)
{
    _field_entry_t **first;     /* First compared entry.  */
    _field_entry_t **second;    /* Second compared entry. */

    first = (_field_entry_t **)a;
    second = (_field_entry_t **)b;

    if ((*first)->eid < (*second)->eid) {
        return (-1);
    } else if ((*first)->eid > (*second)->eid) {
        return (1);
    }
    return (0);
}

/*
 * Function:
 *     _field_entry_get
 * Purpose:
 *     Lookup a FP rule(entry) from a unit ID and slice & rule id choice.
 * Parmeters:
 *     unit    - (IN)BCM device number. 
 *     eid     - (IN)Entry id. 
 *     flags   - (IN)Entry flags to match.
 *     entry_p - (OUT) Entry lookup result.  
 * Returns:
 *     BCM_E_XXX
 */
int
_field_entry_get(int unit, bcm_field_entry_t eid, uint32 flags, 
                  _field_entry_t **entry_p)
{
    _field_entry_t   target;  /* Entry lookup pointer.    */
    _field_entry_t   *f_ent;  /* Entry lookup pointer.    */
    _field_control_t *fc;     /* Field control structure. */
    _field_group_t   *fg;     /* Field group iterator.    */
    uint8  entry_part;        /* Wide entry part number.  */
    int    rv;                /* Operation return status. */
    int    idx;               /* Entry index.             */

    /* Input parameters check. */
    if (NULL == entry_p) {
        return (BCM_E_PARAM);
    }

    /* Reset target entry */
    target.eid = eid;
    f_ent = &target;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    fg = fc->groups; 
    while (NULL != fg)  {
        /* Skip empty groups. */
        if (NULL == fg->entry_arr) {
            fg = fg->next;
            continue;
        }
        idx = _shr_bsearch(fg->entry_arr, fg->group_status.entry_count, 
                           sizeof(_field_entry_t *), (void *)&f_ent,
                           _field_entry_t_compare);
        if (idx >= 0) {
            rv = _bcm_field_entry_flags_to_tcam_part (flags, 
                                                      fg->flags,
                                                      &entry_part);
            *entry_p = fg->entry_arr[idx] + entry_part;
            return (BCM_E_NONE);
        }
        fg = fg->next;
    }
    /* Rule with id == eid not found. */
    return (BCM_E_NOT_FOUND);
}

/*
 * Function:
 *     _field_group_entry_add
 * Purpose:
 *     Insert an entry to field group entry array.
 * Parmeters:
 *     unit    - (IN)BCM device number. 
 *     fg      - (IN)Field group structure.
 *     f_ent   - (IN)Inserted entry structure.
 * Returns:
 *     BCM_E_XXX
 */
int
_field_group_entry_add (int unit, _field_group_t *fg, 
                        _field_entry_t *f_ent)
{
    _field_entry_t **f_ent_arr;   /* Field group entry array.*/ 
    int mem_sz;                   /* Memory size.            */
    int idx;                      /* Entry insertion index.  */
    int tmp;                      /* Temporary iterator.     */

    /* Input parameters check */
    if ((NULL == fg) || (NULL == f_ent)) {
        return (BCM_E_PARAM);
    }

    /* Verify if entry already present in the group . */
    if (NULL != fg->entry_arr) {
        idx = _shr_bsearch(fg->entry_arr, fg->group_status.entry_count,
                           sizeof (_field_entry_t *), &f_ent,
                           _field_entry_t_compare);
        /* Entry already IN. */
        if (idx >= 0) {
            return (BCM_E_NONE);
        }
    } else {
        idx = -1;  /* Insert into 0 location. */
    }

    /* Check if group has enough room for new entry */
    if (fg->group_status.entry_count + 1 > 
        fg->ent_block_count * _FP_GROUP_ENTRY_ARR_BLOCK) {

        mem_sz = _FP_GROUP_ENTRY_ARR_BLOCK * (fg->ent_block_count + 1) *
            sizeof(_field_entry_t *);

        f_ent_arr = NULL;

        _FP_XGS3_ALLOC(f_ent_arr, mem_sz, "field group entries array");
        if (NULL == f_ent_arr) {
            return (BCM_E_MEMORY);
        } 
        /* Copy original array to newly allocated one. */
        if (NULL != fg->entry_arr) {
            mem_sz = _FP_GROUP_ENTRY_ARR_BLOCK * (fg->ent_block_count) *
                sizeof(_field_entry_t *);
            sal_memcpy(f_ent_arr, fg->entry_arr, mem_sz);

            sal_free (fg->entry_arr);  
        }
        fg->entry_arr = f_ent_arr;
        fg->ent_block_count++;
    }
    /* Make room for inserted entry */
    idx = (((-1) * idx) - 1);
    tmp = fg->group_status.entry_count - 1;
    while (tmp >= idx) {
    /*    coverity[var_deref_op : FALSE]    */
        fg->entry_arr[tmp + 1] = fg->entry_arr[tmp];
        tmp--;
    }
    fg->entry_arr[idx] = f_ent;
    fg->group_status.entry_count++;
    return (BCM_E_NONE);
}


/*
 * Function:
 *     _field_group_entry_delete
 * Purpose:
 *     Remove an entry from field group entry array.
 * Parmeters:
 *     unit    - (IN)BCM device number. 
 *     fg      - (IN)Field group structure.
 *     f_ent   - (IN)Removed entry structure.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_entry_delete(int unit, _field_group_t *fg, 
                        _field_entry_t *f_ent)
{
    int idx;                      /* Entry insertion index.  */
    int tmp;                      /* Temporary iterator.     */

    /* Input parameters check */
    if ((NULL == fg) || (NULL == f_ent)) {
        return (BCM_E_PARAM);
    }

    /* Make sure group entry array was not deallocated. */
    if (NULL == fg->entry_arr) {
        return (BCM_E_INTERNAL);
    }

    /* Verify if entry already present in the group . */
    idx = _shr_bsearch(fg->entry_arr, fg->group_status.entry_count,
                       sizeof (_field_entry_t *), &f_ent,
                       _field_entry_t_compare);
    if (idx < 0) {
        return (BCM_E_NOT_FOUND);
    }

    /* Make room for inserted entry */
    tmp = idx;
    while (tmp < fg->group_status.entry_count - 1) {
        fg->entry_arr[tmp] = fg->entry_arr[tmp + 1];
        tmp++;
    }
    fg->group_status.entry_count--;
    fg->entry_arr[fg->group_status.entry_count] = NULL;
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_entry_get_by_id
 * Purpose:
 *     Lookup a complete FP rule(entry) from a unit & rule id choice.
 * Parmeters:
 *     unit      - (IN)BCM device number. 
 *     eid       - (IN)Entry id. 
 *     entry_arr - (OUT) Entry lookup result array. (Array of pointers to 
 *                       primary/secondary/teriary ... parts of entry.   
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_entry_get_by_id(int unit, bcm_field_entry_t eid, 
                       _field_entry_t **entry_arr)
{
    int    rv;     /* Operation return status. */

    /* Input parameters check. */
    if (NULL == entry_arr) {
        return (BCM_E_PARAM);
    }

    /* Initialize entry array. */
    *entry_arr = NULL;

    /* Extract primary entry. */
    rv = _field_entry_get(unit, eid, _FP_ENTRY_PRIMARY, entry_arr);
    
    return (rv);
}

/*
 * Function:
 *     _bcm_field_entry_qual_get
 *
 * Purpose:
 *     Lookup a _field_entry_t from a unit ID taking into account mode. Since
 *     double and triple-wide modes can have multiple physical entries with the
 *     same Entry ID, 
 *
 * Parmeters:
 *     unit    - (IN)BCM device number.
 *     eid     - (IN)Entry id.
 *     qual    - (IN)Qualifier used to select the correct slice
 *     entry_p - (OUT)Lookup result entry.  
 *
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_entry_qual_get(int unit, bcm_field_entry_t entry,
                          int qual, _field_entry_t **entry_p)
{
    _bcm_field_group_qual_t *q_arr;  /* Qualifiers array.               */
    int             parts_count;     /* Number of entry parts.          */
    int             part_idx;        /* Entry parts iteration index.    */
    int             qual_idx;        /* Part qualifiers iteration index.*/
    uint8           found;           /* Entry lookup flags.             */
    _field_group_t  *fg;             /* FP group info structure.        */
    int             rv;              /* Operation return status.        */

    FP_VVERB(("_bcm_field_entry_qual_get\n"));

    /* Input parameters check. */
    if (NULL == entry_p) {
        return (BCM_E_PARAM);
    }

    /* Initialization. */
    found = FALSE;

    /* Search the entry by eid. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, entry_p);
    BCM_IF_ERROR_RETURN(rv);

    fg = (*entry_p)->group;
    if (NULL == fg) {
        return (BCM_E_INTERNAL);
    }

    /* If it's an external slice, then the qualifier has to be in the primary
     * entry, since that's the only entry it has. */
    if (fg->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        return (BCM_E_NONE);
    }
    
    /* Get number of entry parts we have to read. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Iterate over all entry parts. */
    for (part_idx = 0; part_idx < parts_count; part_idx++) {
        /* Get part qualifiers array. */
        q_arr = fg->qual_arr + part_idx; 
        /* Search array by qualifier id. */
        for (qual_idx = 0; qual_idx < q_arr->size; qual_idx++) {
            if ((uint16)qual == q_arr->qid_arr[qual_idx]) {
                found = TRUE;
                break;
            }
        }
        if (found) {
            break;
        }
    }

    /* Check lookup status. */
    if (FALSE == found) {
        return (BCM_E_NOT_FOUND);
    }

    *entry_p += part_idx;
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_policer_get
 * Purpose:
 *     Lookup a Policer description structure by policer id.
 * Parmeters:
 *     unit      - (IN)BCM device number. 
 *     pid       - (IN)Policer id. 
 *     policer_p - (OUT) Policer lookup result.  
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_policer_get(int unit, bcm_policer_t pid, 
                       _field_policer_t **policer_p)
{
    _field_policer_t *f_pl; /* Policer lookup pointer.  */
    _field_control_t *fc;   /* Field control structure. */
    uint32 hash_index;      /* Entry hash.              */

    /* Input parameters check. */
    if (NULL == policer_p) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    hash_index = pid & _FP_HASH_INDEX_MASK(fc);
    f_pl  =  fc->policer_hash[hash_index];
    while (NULL != f_pl) {
        /* Match entry id. */
        if (f_pl->pid == pid) {
            *policer_p = f_pl;
            return (BCM_E_NONE);
        }
        f_pl = f_pl->next;
    }

    /* Policer with pid == pid was not found. */
    return (BCM_E_NOT_FOUND);
}

/*
 * Function:
 *      _field_policer_destroy2
 * Purpose:
 *      Deinitialize a policer entry.
 * Parameters:
 *      unit    - (IN) Unit number.
 *      fc      - (IN) Field control structure.
 *      f_pl    - (IN) Internal policer descriptor.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
STATIC int 
_field_policer_destroy2(int unit, _field_control_t *fc,
                        _field_policer_t *f_pl)
{
    /* Input parameters check. */ 
    if ((NULL == fc) || (NULL == f_pl)) {
        return (BCM_E_PARAM);
    }

    /* Reject destroy if policer is in use. */ 
    if (f_pl->sw_ref_count > 1) {
        return (BCM_E_BUSY);
    }

    /* Remove policer for lookup hash. */
    _FP_HASH_REMOVE(fc->policer_hash, _field_policer_t, f_pl, 
                    (f_pl->pid & _FP_HASH_INDEX_MASK(fc)));


    /* De-allocate policer descriptor. */
    sal_free(f_pl);

    /* Decrement number of active policers. */
    if (fc->policer_count > 0) {
        fc->policer_count--;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_policer_destroy
 * Purpose:
 *      Deinitialize a policer entry.
 * Parameters:
 *      unit    - (IN) Unit number.
 *      pid     - (IN) Policer id.  
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_field_policer_destroy(int unit, bcm_policer_t pid)
{
    _field_control_t    *fc;               /* Field control structure.     */
    _field_policer_t    *f_pl;             /* Internal policer descriptor. */
    int                 rv;                /* Operation return status.     */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Find policer info. */
    rv = _bcm_field_policer_get(unit, pid, &f_pl);
    if (BCM_FAILURE(rv)) {
        return (rv);
    }

    return _field_policer_destroy2(unit, fc, f_pl);
}

/*
 * Function:
 *      _field_policer_hw_flags_set
 * Purpose:
 *      Update policer installation is required flag.    
 * Parameters:
 *      unit    - (IN) Unit number.
 *      f_pl    - (IN/OUT) Internal policer descriptor.
 *      flags   - (IN) Internal flags. 
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
STATIC int 
_field_policer_hw_flags_set(int unit, _field_policer_t *f_pl, uint32 flags)
{
    /* Input parameters check. */
    if (NULL == f_pl) {
        return (BCM_E_PARAM);
    }

    f_pl->hw_flags |= flags;

    switch (f_pl->cfg.mode) {
      case bcmPolicerModeCommitted:
          f_pl->hw_flags |= _FP_POLICER_COMMITTED_DIRTY;
          break;
      case bcmPolicerModePeak:
          f_pl->hw_flags |= _FP_POLICER_PEAK_DIRTY;
          break;
      case bcmPolicerModeSrTcm:
      case bcmPolicerModeTrTcm:
      case bcmPolicerModeTrTcmDs:
      case bcmPolicerModeCoupledTrTcmDs:
      case bcmPolicerModeSrTcmModified:
          f_pl->hw_flags |= _FP_POLICER_DIRTY;
          break;
      default:
          return (BCM_E_UNAVAIL);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_policer_id_alloc
 * Purpose:
 *      Allocate a policer id.
 * Parameters:
 *      unit    - (IN) BCM device number.
 *      pid     - (OUT) Policer id.  
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_field_policer_id_alloc(int unit, bcm_policer_t *pid)
{
    int               max_count;           /* Maximum number of pid to try.*/
    _field_policer_t  *f_pl;               /* Field policer descriptor.    */
    int               rv;                  /* Operation return status.     */ 
    static uint32  last_allocated_pid = 0; /* Policer id alloc tracker.    */ 
    
    /* Input parameters check. */
    if (NULL == pid) {
        return (BCM_E_PARAM);
    }

    max_count = _FP_ID_MAX;
    while (max_count--) {
        last_allocated_pid++;
        if (_FP_ID_MAX == last_allocated_pid) {
            last_allocated_pid = _FP_ID_BASE;
        }
        rv = _bcm_field_policer_get(unit, last_allocated_pid, &f_pl);
        if (BCM_E_NOT_FOUND == rv) {
            *pid = last_allocated_pid;
            return (BCM_E_NONE);
        }
        if (BCM_FAILURE(rv)) {
            return (rv);
        }
    }
    return (BCM_E_RESOURCE);
}


/*
 * Function:
 *      _field_policer_mode_support
 * Purpose:
 *      Validate policer mode support.
 * Parameters:
 *      unit    - (IN) BCM device number.
 *      f_ent   - (IN) Field entry policer attached. 
 *      level   - (IN) Level policer attached.
 *      f_pl    - (IN) Policer descriptor.
 * Returns:
 *      BCM_E_XXX
 */
STATIC int 
_field_policer_mode_support(int unit, _field_entry_t *f_ent,
                            int level, _field_policer_t *f_pl)
{
    int rv = BCM_E_UNAVAIL;   /* Operation return status.     */

    /* Level 1 policers mode must be bcmPolicerModePeak */
    if (1 == level) {

#ifdef BCM_TRIDENT_SUPPORT
        if (SOC_IS_TD_TT(unit)) {
            /* Trident device does not support Level1 policers. */
            return (BCM_E_UNAVAIL);
        } 
#endif
        if (((SOC_IS_TRX(unit)) &&
            (_BCM_FIELD_STAGE_INGRESS == f_ent->group->stage_id)) ||
            ((_BCM_FIELD_STAGE_EXTERNAL == f_ent->group->stage_id) &&
            (SOC_IS_TRIUMPH(unit) || SOC_IS_TRIUMPH2(unit)))) {
            rv = (f_pl->cfg.mode == bcmPolicerModePeak) ? \
                 (BCM_E_NONE) : (BCM_E_PARAM);
        }
        return (rv);
    }

    switch (f_pl->cfg.mode) {
      case bcmPolicerModeTrTcm:
      case bcmPolicerModeSrTcm:
      case bcmPolicerModeCommitted:
      case bcmPolicerModePeak:
      case bcmPolicerModeGreen:
          rv = BCM_E_NONE;
          break;
      case bcmPolicerModePassThrough:
          if (SOC_IS_TRX(unit)) {
              rv = BCM_E_NONE;
          } else if ((SOC_IS_FIREBOLT2(unit)) &&
                     (_BCM_FIELD_STAGE_EGRESS == f_ent->group->stage_id)) {
              rv = BCM_E_NONE;
          }
          break;
      case bcmPolicerModeTrTcmDs:
          if (SOC_IS_TRX(unit)) {
              rv = BCM_E_NONE;
          } 
          break;
      case bcmPolicerModeSrTcmModified:
      case bcmPolicerModeCoupledTrTcmDs:
          if ((soc_feature(unit, soc_feature_field_virtual_queue)) &&
              (_BCM_FIELD_STAGE_INGRESS == f_ent->group->stage_id)) {
              rv = BCM_E_NONE;
          }
          break;
      default:
          rv = BCM_E_PARAM;
          break;
    }
    return (rv);
}



/*
 * Function:
 *      _field_policer_create
 * Purpose:
 *      Initialize a policer entry.
 * Parameters:
 *      unit    - (IN) BCM device number.
 *      pol_cfg - (IN) Policer configuration.
 *      flags   - (IN) HW/API specific flags. 
 *      pid     - (OUT) Policer id.  
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
STATIC int 
_field_policer_create(int unit, bcm_policer_config_t *pol_cfg, 
                      uint32 flags, bcm_policer_t *pid)
{
    _field_control_t    *fc;          /* Field control structure.     */
    int                 rv;           /* Operation return status.     */
    _field_policer_t    *f_pl = NULL; /* Internal policer descriptor. */

    /* Input parameters check. */
    if (NULL == pol_cfg) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Generate policer id. */
    if (0 == (pol_cfg->flags & BCM_POLICER_WITH_ID)) {
        BCM_IF_ERROR_RETURN (_field_policer_id_alloc(unit, pid));
    } else {
        /* Check if policer id is already in use. */
        rv = _bcm_field_policer_get(unit, *pid, &f_pl);
        if (BCM_SUCCESS(rv)) {
            /* Verify that replace flag is set. */
            if(0 == (pol_cfg->flags & BCM_POLICER_REPLACE)) {
                return (BCM_E_EXISTS);
            }

            /* Make sure police is not attached to any entry. */
            if (1 != f_pl->sw_ref_count) {
                return (BCM_E_BUSY);
            }
            /* Copy new configuration. */
            sal_memcpy(&f_pl->cfg, pol_cfg, sizeof(bcm_policer_config_t)); 

            /* Set policer "dirty" flag and return. */
            rv = _field_policer_hw_flags_set(unit, f_pl, flags);
            return (rv);
        }
    }

    /* Allocate policer descriptor. */
    _FP_XGS3_ALLOC(f_pl, sizeof (_field_policer_t), "Field policer");
    if (NULL == f_pl) {
        return (BCM_E_MEMORY);
    }

    /* Copy policer configuration. */
    sal_memcpy(&f_pl->cfg, pol_cfg, sizeof(bcm_policer_config_t)); 

    /* Set policer "dirty" flags. */
    rv = _field_policer_hw_flags_set(unit, f_pl, flags);
    if (BCM_FAILURE(rv)) {
        sal_free(f_pl);
        return (rv);
    }

    /* Initialize reference count to 1. */
    f_pl->sw_ref_count = 1;

    /* Set hw index to - no hw resources allocated. */
    f_pl->pool_index = _FP_INVALID_INDEX;
    f_pl->hw_index = _FP_INVALID_INDEX;

    /* Initialize policer id. */
    f_pl->pid = *pid;

    /* Insert policer into policers hash. */
    _FP_HASH_INSERT(fc->policer_hash, f_pl, (*pid & _FP_HASH_INDEX_MASK(fc)));

    /* Increment number of active policers. */
    fc->policer_count++;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_meter_mem_get
 * Purpose:
 *     Get meter memory name.
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     stage_fc  - (IN) Stage field control.
 *     mem       - (OUT) Meter memory.
 * Returns:
 *     BCM_E_XXX   -
 */
STATIC int
_field_meter_mem_get(int unit, _field_stage_t *stage_fc, soc_mem_t *mem)
{
    /* Input parameters check. */
    if ((NULL == stage_fc)  || (NULL == mem)) {
        return (BCM_E_PARAM);
    }

    switch (stage_fc->stage_id) {
      case _BCM_FIELD_STAGE_INGRESS:
          *mem = FP_METER_TABLEm;
          break;
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
      case _BCM_FIELD_STAGE_EGRESS:
          *mem = EFP_METER_TABLEm;
          break;
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
      default:
          return (BCM_E_PARAM);
    }
    return (BCM_E_NONE);
}

/*
 * Function: _field_counter_mem_get
 *
 * Description:
 *      Service routine used to extract unit field counters memories
 *
 * Parameters:
 *      unit            - (IN) BCM device number.
 *      fc              - (IN) Field control structure. 
 *      stage_fc        - (IN) Stage field control structure. 
 *      counter_x_mem   - (OUT)First counters memory.
 *      counter_y_mem   - (OUT)Second counters memory.
 * Returns:
 *      BCM_E_XXX
 */
int
_field_counter_mem_get(int unit, _field_stage_t *stage_fc, 
                       soc_mem_t *counter_x_mem, soc_mem_t *counter_y_mem)
{
    if (NULL == stage_fc || NULL == counter_x_mem || NULL == counter_y_mem) {
        return (BCM_E_PARAM);
    }

    *counter_x_mem = INVALIDm;
    *counter_y_mem = INVALIDm;

    if (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
#ifdef BCM_FIREBOLT_SUPPORT
        if (SOC_IS_FBX(unit)) {
#ifdef BCM_BRADLEY_SUPPORT
            if (soc_feature(unit, soc_feature_two_ingress_pipes)) {
                *counter_x_mem = FP_COUNTER_TABLE_Xm;
                *counter_y_mem = FP_COUNTER_TABLE_Ym;
            } else 
#endif /* BCM_BRADLEY_SUPPORT */ 
            {
                *counter_x_mem = FP_COUNTER_TABLEm;
            }
        } else
#endif /* BCM_FIREBOLT_SUPPORT */
#ifdef BCM_EASYRIDER_SUPPORT
        if (SOC_IS_EASYRIDER(unit)) {
            *counter_x_mem = FP_COUNTER_INTm;
        } else
#endif /* BCM_EASYRIDER_SUPPORT */
        {
           return (BCM_E_UNAVAIL);
        }
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) 
    } else if (_BCM_FIELD_STAGE_LOOKUP== stage_fc->stage_id) {
        return (BCM_E_NONE);
    } else if (_BCM_FIELD_STAGE_EGRESS == stage_fc->stage_id) {
        if (soc_feature(unit, soc_feature_two_ingress_pipes)) {
            *counter_x_mem = EFP_COUNTER_TABLE_Xm; 
            *counter_y_mem = EFP_COUNTER_TABLE_Ym; 
        } else {
            *counter_x_mem = EFP_COUNTER_TABLEm; 
        }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    } else if (_BCM_FIELD_STAGE_EXTERNAL == stage_fc->stage_id) {
        *counter_x_mem = EXT_FP_CNTRm;
    } else { 
        return (BCM_E_INTERNAL);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_entry_counter_move
 * Purpose:
 *     Move the counter for an entry moving across a slice
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     stage_fc     - (IN) Stage field control.
 *     old_slice    - (IN) Old counter slice number.
 *     old_hw_index - (IN) Old counter hw index.
 *     f_st         - (IN) New statistics entity descriptor.
 * Returns:
 *     BCM_E_XXX   
 */
int
_bcm_field_entry_counter_move(int unit, _field_stage_t *stage_fc, 
                              uint8 old_slice, int old_hw_index, 
                              _field_stat_t *f_st_old,
                              _field_stat_t *f_st)
{
    soc_mem_t counter_x_mem, counter_y_mem; /* Counter memories         */
    _field_control_t *fc;                   /* FP control information   */
    uint32 flags = 0;                       /* Bytes/Packets Stats type */
    uint64 value;                           /* Hardware Stats value     */
    int new_idx1 = _FP_INVALID_INDEX;       /* Primary Hw stats index   */
    int new_idx2 = _FP_INVALID_INDEX;       /* Secondary Hw stats index */
    int nstat;                              /* Number of stats          */
    int rv = BCM_E_INTERNAL;                /* Operation return status  */

    /* Get field control structure. */
    rv = _field_control_get(unit, &fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Get the counter memories */
    rv = _field_counter_mem_get(unit, stage_fc, &counter_x_mem, &counter_y_mem);
    BCM_IF_ERROR_RETURN(rv);

    for (nstat = 0; nstat < f_st_old->nstat; nstat++) {
        /* Get Stat value from old hardware index */
        rv = _field_stat_value_get(unit, f_st_old, f_st_old->stat_arr[nstat],
                &value);
        BCM_IF_ERROR_RETURN(rv);

        if (_BCM_FIELD_STAGE_EXTERNAL != stage_fc->stage_id) {
            /* Get Stat New hardware index values */
            rv = fc->functions.fp_stat_index_get(unit, f_st,
                f_st->stat_arr[nstat], &new_idx1, &new_idx2, &flags);
            BCM_IF_ERROR_RETURN(rv);
        } else if (_BCM_FIELD_STAGE_EXTERNAL == stage_fc->stage_id) {
            new_idx1 = f_st->hw_index;
        }

        /* Check if new hardware index is valid */
        if (_FP_INVALID_INDEX == new_idx1) {
            return (BCM_E_INTERNAL);
        }

        if ((flags & _FP_STAT_BYTES)
            && (stage_fc->flags & _FP_STAGE_SEPARATE_PACKET_BYTE_COUNTERS))  {
            /*
             * For devices that do not support separate packet and byte counters
             * only _field_x32_counters is used.
             */
                
#if defined(BCM_TRX_SUPPORT)
            /* Zero the accumulated part at new_idx1 */
            COMPILER_64_ZERO(stage_fc->_field_x64_counters[new_idx1].
                accumulated_counter);

            /* Copy the accumulated part value */
            COMPILER_64_OR(stage_fc->_field_x64_counters[new_idx1].
                accumulated_counter, value);

            /* Zero the last_hw_value at new_idx1 */
            COMPILER_64_ZERO(stage_fc->_field_x64_counters[new_idx1].
                last_hw_value);

            /* Zero Y-Pipeline counter values */
            if (INVALIDm != counter_y_mem) {
                COMPILER_64_ZERO(stage_fc->_field_y64_counters[new_idx1].
                    accumulated_counter);
                COMPILER_64_ZERO(stage_fc->_field_y64_counters[new_idx1].
                    last_hw_value);
            }

            /* Zero counters at secondary index */
            if (_FP_INVALID_INDEX != new_idx2) {
                COMPILER_64_ZERO(stage_fc->_field_x64_counters[new_idx2].
                    accumulated_counter);
                COMPILER_64_ZERO(stage_fc->_field_x64_counters[new_idx2].
                    last_hw_value);

                /* Zero Y-Pipeline counter values at secondary index */
                if (INVALIDm != counter_y_mem) {
                    COMPILER_64_ZERO(stage_fc->_field_y64_counters[new_idx2].
                        accumulated_counter);
                    COMPILER_64_ZERO(stage_fc->_field_y64_counters[new_idx2].
                        last_hw_value);
                }
            }
#endif
        } else {

            /* Zero the accumulated part at new_idx1 */
            COMPILER_64_ZERO(stage_fc->_field_x32_counters[new_idx1].
                accumulated_counter);

            /* Copy the accumulated part */
            COMPILER_64_OR(stage_fc->_field_x32_counters[new_idx1].
                accumulated_counter, value);

            /* Zero the last_hw_value at new_idx1 */
            stage_fc->_field_x32_counters[new_idx1].last_hw_value = 0;

            /* Zero Y-Pipeline packet counter values */
            if (INVALIDm != counter_y_mem) {
#if defined(BCM_SCORPION_SUPPORT)
                COMPILER_64_ZERO(stage_fc->_field_y32_counters[new_idx1].
                    accumulated_counter);

                /* Zero the last_hw_value at new_idx1 */
                stage_fc->_field_y32_counters[new_idx1].last_hw_value = 0;
#endif
            }

            /* Zero counters at secondary index */
            if (_FP_INVALID_INDEX != new_idx2) {
                /* Zero the accumulated part at new_idx2 */
                COMPILER_64_ZERO(stage_fc->_field_x32_counters[new_idx2].
                    accumulated_counter);

                /* Zero the last_hw_value at new_idx2 */
                stage_fc->_field_x32_counters[new_idx2].last_hw_value = 0;

                /* Zero Y-Pipeline packet counter values at secondary index */
                if (INVALIDm != counter_y_mem) {
#if defined(BCM_SCORPION_SUPPORT)
                    COMPILER_64_ZERO(stage_fc->_field_y32_counters[new_idx2].
                        accumulated_counter);

                    /* Zero the last_hw_value at new_idx2 */
                    stage_fc->_field_y32_counters[new_idx2].last_hw_value = 0;
#endif
                }
            }
        }
        
        COMPILER_64_ZERO(value);     
        rv = _field_stat_value_set(unit, f_st_old, f_st_old->stat_arr[nstat],
                  value);
        BCM_IF_ERROR_RETURN(rv);
    }
    return rv;
}

/*
 * Function:
 *     _field_entry_meter_move
 * Purpose:
 *     Move the meters for an entry moving across a slice
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     stage_fc     - (IN) Stage field control.
 *     old_slice    - (IN) Old meter slice number.
 *     old_hw_index - (IN) Old meter hw index.
 *     f_pl         - (IN) New meter descriptor.
 * Returns:
 *     BCM_E_XXX   
 */
STATIC int
_field_entry_meter_move(int unit, _field_stage_t *stage_fc, 
                        uint8 old_slice, int old_hw_index, 
                        _field_policer_t *f_pl)
{
    uint32 buf[SOC_MAX_MEM_FIELD_WORDS];  /* Meter memory entry buffer. */
    soc_mem_t mem;                        /* Meter memory.              */
    int old_index;                        /* Old meter index in memory. */
    int new_index;                        /* New meter index in memory. */


    BCM_IF_ERROR_RETURN(_field_meter_mem_get(unit, stage_fc, &mem));

    old_index =  stage_fc->slices[old_slice].start_tcam_idx +
        (2 * old_hw_index);

    new_index =  stage_fc->slices[f_pl->pool_index].start_tcam_idx +
        (2 * f_pl->hw_index);

    /* Meters come in pairs => max index + 1 should also be valid. */
    if ((old_index < soc_mem_index_min(unit, mem)) ||
        ((old_index + 1) > soc_mem_index_max(unit, mem)) ||
        (new_index < soc_mem_index_min(unit, mem)) ||
        ((new_index + 1) > soc_mem_index_max(unit, mem))) {
        return (BCM_E_PARAM);
    }

    /* Copy meter from old location to a new one. */
    sal_memset(buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    BCM_IF_ERROR_RETURN
        (soc_mem_read(unit, mem, MEM_BLOCK_ANY, old_index, buf));
    BCM_IF_ERROR_RETURN
        (soc_mem_write(unit, mem, MEM_BLOCK_ALL, new_index, buf));

    sal_memset(buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    BCM_IF_ERROR_RETURN
        (soc_mem_read(unit, mem, MEM_BLOCK_ANY, old_index + 1, buf));
    BCM_IF_ERROR_RETURN
        (soc_mem_write(unit, mem, MEM_BLOCK_ALL, new_index + 1, buf));
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_meter_pool_alloc
 *
 * Purpose:
 *     Allocate/Find meter pool with free meters 
 * 
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     stage_fc - (IN) Stage field control structure.
 *     level    - (IN) Meter attachment level.
 *     slice_id - (IN) Slice base index.
 *     pool_idx - (OUT) Meter pool index.
 * Returns:
 *     BCM_E_XXX
 *
 */
STATIC int
_field_meter_pool_alloc(int unit, _field_stage_t *stage_fc, 
                        uint8 level, uint8 slice_id, uint8 *pool_idx)
{
    _field_meter_pool_t *f_mp;          /* Meter pool descriptor. */
    int                 idx;            /* Pool iteration index.  */
    int                 free_pool;      /* Free meter pool.       */


    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == pool_idx)) {
        return (BCM_E_PARAM);
    }

    free_pool = _FP_INVALID_INDEX;
    for (idx = 0 ; idx < stage_fc->num_meter_pools; idx++) { 
        f_mp = stage_fc->meter_pool[idx];
        if (NULL == f_mp) {
            return (BCM_E_INTERNAL);
        }

        /* If we have a matchin pool with free entries - just use it. */
        if ((f_mp->slice_id == slice_id) && 
            (f_mp->level    == level) && 
            (f_mp->free_meters > 0)) {
            *pool_idx = idx;
            return (BCM_E_NONE);
        }

        /* Preserve first free pool */
        if ((_FP_INVALID_INDEX  == free_pool) && 
            (_FP_INVALID_INDEX  == f_mp->slice_id)) {
            free_pool = idx;
        }
    }


    /* We have to use free pool at this point. */
    if (_FP_INVALID_INDEX == free_pool) {
        return (BCM_E_RESOURCE);
    }

    f_mp = stage_fc->meter_pool[free_pool];
    f_mp->slice_id = slice_id;
    f_mp->level = level;
    *pool_idx = free_pool;
    return (BCM_E_NONE);
} 


/*
 * Function:
 *     _field_meter_pool_free
 *
 * Purpose:
 *     Unreserve a meter pool. 
 * 
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     stage_fc - (IN) Stage field control structure.
 *     pool_idx - (IN) Meter pool index.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_meter_pool_free(int unit, _field_stage_t *stage_fc, uint8 pool_idx)
{
    _field_meter_pool_t *f_mp;          /* Meter pool descriptor. */

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    f_mp = stage_fc->meter_pool[pool_idx];
    if (NULL == f_mp) {
        return (BCM_E_INTERNAL);
    }

    /* Make sure pool entries are not in use. */
    if (f_mp->free_meters != f_mp->size) {
        return (BCM_E_BUSY);
    }

    f_mp->slice_id = _FP_INVALID_INDEX;
    f_mp->level = 0;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_meter_pool_entry_free
 *
 * Purpose:
 *     Free meter pool entry.
 *     if necessary free the pool itself.
 * 
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     stage_fc  - (IN) Stage field control structure.
 *     f_pl      - (IN) Policer descriptor.
 * Returns:
 *     BCM_E_XXX
 *
 */
STATIC int
_field_meter_pool_entry_free(int unit, _field_stage_t *stage_fc, 
                              _field_policer_t *f_pl)
{
    _field_meter_pool_t *f_mp;          /* Meter pool descriptor. */

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == f_pl)) {
        return (BCM_E_PARAM);
    }

    /* Meter pool index sanity check. */
    if (stage_fc->num_meter_pools <= f_pl->pool_index) {
        return (BCM_E_PARAM);
    }

    f_mp = stage_fc->meter_pool[f_pl->pool_index];

    /* Meter index in the pool sanity check. */
    if (f_mp->size <= f_pl->hw_index) {
        return (BCM_E_PARAM);
    }

    _FP_METER_BMP_REMOVE(f_mp->meter_bmp, f_pl->hw_index);
    f_mp->free_meters++;

    /* Free empty pool. */
    if (f_mp->free_meters == f_mp->size) {
        BCM_IF_ERROR_RETURN 
            (_field_meter_pool_free(unit, stage_fc, f_pl->pool_index));
    }

    /* Reset pool and hw index information in policer structure. */
    f_pl->pool_index = _FP_INVALID_INDEX;
    f_pl->hw_index = _FP_INVALID_INDEX;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_meter_pool_entry_alloc
 *
 * Purpose:
 *     Allocate meter pool entry.
 * 
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     stage_fc  - (IN) Stage field control structure.
 *     pool_idx  - (IN) Meter pool index.
 *     meter_idx - (OUT)Allocated entry index.
 * Returns:
 *     BCM_E_XXX
 *
 */
STATIC int
_field_meter_pool_entry_alloc(int unit, _field_stage_t *stage_fc, 
                              uint8 pool_slice_id, _field_policer_t *f_pl)
{
    _field_meter_pool_t *f_mp;          /* Meter pool descriptor. */
    uint8               pool_idx;       /* Meter pool index.      */
    int                 idx;            /* Pool iteration index.  */

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == f_pl)) {
        return (BCM_E_PARAM);
    }

    if (f_pl->level >= _FP_POLICER_LEVEL_COUNT) {
        return (BCM_E_PARAM);
    }

    /* Allocate meter pool with free meters. */
    BCM_IF_ERROR_RETURN (_field_meter_pool_alloc(unit, stage_fc, f_pl->level,
                                                 pool_slice_id, &pool_idx));
    f_mp = stage_fc->meter_pool[pool_idx];

    /* Reserve unused meter. */
    for (idx = 0; idx < f_mp->size; idx++) {
        if (0 == _FP_METER_BMP_TEST(f_mp->meter_bmp, idx)) {
            _FP_METER_BMP_ADD(f_mp->meter_bmp, idx);
            f_mp->free_meters--;
            f_pl->pool_index = pool_idx;
            f_pl->hw_index = idx;
            return (BCM_E_NONE);
        }
    }

    /* Never reached - pool alloc makes sure at least one meter is available. */
    if (f_mp->free_meters == f_mp->size) {
        BCM_IF_ERROR_RETURN (_field_meter_pool_free(unit, stage_fc, pool_idx));
    }
    return (BCM_E_RESOURCE);
}

/*
 * Function:
 *     _field_meterpool_hw_entry_alloc
 *
 * Purpose:
 *     Allocate field entry meter from a meter pool.
 * 
 * Parameters:
 *     unit  - (IN) BCM device number.
 *     f_ent - (IN) Field entry structure.
 *     f_pl  - (IN) Field policer descriptor. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_meterpool_hw_entry_alloc (int unit, _field_entry_t *f_ent,
                                 _field_policer_t *f_pl)
{
    _field_stage_id_t      stage_id;  /* Stage id used for metering.          */
    _field_stage_t         *stage_fc; /* Field stage control structure.       */
    _field_group_t         *fg;       /* Field group structure.               */
    uint8                  pool_sid;  /* Key to ensure single update per hit. */

    /* Input parameters check. */
    if ((NULL == f_ent) || (NULL == f_pl)) {
        return (BCM_E_PARAM);
    }

    fg = f_ent->group;
    stage_id = (_BCM_FIELD_STAGE_EXTERNAL == fg->stage_id) ? \
               _BCM_FIELD_STAGE_INGRESS : fg->stage_id;

    /* Get meter pool stage control. */ 
    BCM_IF_ERROR_RETURN(_field_stage_control_get (unit, stage_id, &stage_fc));

    /* Generate unique pool id.  */
    if (_BCM_FIELD_STAGE_EXTERNAL == fg->stage_id) {
        pool_sid = stage_fc->tcam_slices;
    } else {
        pool_sid = fg->slices->slice_number;
    }

    /* Allocate an entry within the pool. */
    BCM_IF_ERROR_RETURN 
        (_field_meter_pool_entry_alloc(unit, stage_fc, pool_sid, f_pl));
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_slice_meter_free
 *
 * Purpose:
 *     Free slice meter. 
 * 
 * Parameters:
 *     unit  - (IN) BCM device number.
 *     f_ent - (IN) Field entry structure.
 *     f_pl  - (IN) Field policer descriptor. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_slice_meter_free(int unit, _field_entry_t *f_ent,
                          _field_policer_t *f_pl)
{
    _field_stage_t         *stage_fc; /* Field stage control structure. */
    _field_slice_t         *fs;       /* Field slice structure.         */
#if defined (BCM_FIREBOLT_SUPPORT)
    int                     idx;
#endif

    if ((NULL == f_ent) || (NULL == f_pl)) {
        return (BCM_E_PARAM);
    }

    /* Get field stage control structure. */
    BCM_IF_ERROR_RETURN
        (_field_stage_control_get(unit, f_ent->group->stage_id, &stage_fc));

    /* Get slice policer installed in. */
    fs =  stage_fc->slices + (f_pl->pool_index);

    /* Calculate meter index in the slice. */
    if (f_pl->hw_index >= fs->meters_count) {
        return (BCM_E_INTERNAL);
    }

#if defined (BCM_FIREBOLT_SUPPORT)
    /* Mark meter as free in the slice. */
    if (SOC_IS_FB_FX_HX(unit)) {
        idx = f_pl->hw_index * 2;
        if ((bcmPolicerModePeak != f_pl->cfg.mode) &&
            (bcmPolicerModeCommitted != f_pl->cfg.mode)) {
            _FP_METER_BMP_REMOVE(fs->meter_bmp, idx);
            _FP_METER_BMP_REMOVE(fs->meter_bmp, idx + 1);
        } else {
            if (bcmPolicerModePeak == f_pl->cfg.mode) {
                _FP_METER_BMP_REMOVE(fs->meter_bmp, idx);
            }
            if (bcmPolicerModeCommitted == f_pl->cfg.mode) {
                _FP_METER_BMP_REMOVE(fs->meter_bmp, idx + 1);
            }
        }
    } else 
#endif
    {
        _FP_METER_BMP_REMOVE (fs->meter_bmp, f_pl->hw_index);
    }

    f_pl->hw_index   = _FP_INVALID_INDEX;
    f_pl->pool_index = _FP_INVALID_INDEX;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_slice_meter_alloc
 *
 * Purpose:
 *     Allocate a policer for an entry from a slice.
 * 
 * Parameters:
 *     unit      - (IN) BCM device number.  
 *     fs        - (IN) Slice policer will be installed in.
 *     f_pl      - (IN) Policer descriptor.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_slice_meter_alloc(int unit, _field_slice_t *fs, _field_policer_t *f_pl) 
{
    int              idx;          /* Policer iteration index. */

    /* Input parameters check. */
    if ((NULL == f_pl) || (NULL == fs)) {
        return (BCM_E_PARAM);
    }

    /* Find unused meter in the slice. */
    for (idx = 0; idx < fs->meters_count; idx++) {
#if defined (BCM_FIREBOLT_SUPPORT)
        if (SOC_IS_FB_FX_HX(unit)) {
            if ((bcmPolicerModePeak != f_pl->cfg.mode) &&
                (bcmPolicerModeCommitted != f_pl->cfg.mode)) {
                if (0 != (idx % 2)) {
                    /* skip odd */
                    continue;
                }    
                if ((0 == _FP_METER_BMP_TEST(fs->meter_bmp, idx)) && 
                    (0 == _FP_METER_BMP_TEST(fs->meter_bmp, idx + 1))) {
                        _FP_METER_BMP_ADD(fs->meter_bmp, idx);
                        _FP_METER_BMP_ADD(fs->meter_bmp, (idx + 1));
                        f_pl->pool_index =  fs->slice_number;
                        f_pl->hw_index   =  idx / 2 ;
                        break;
                }
            }

            if (0 == _FP_METER_BMP_TEST(fs->meter_bmp, idx)) {
                /* Odd index reserved for committed meters */
                if ((0 != (idx % 2)) && 
                    (bcmPolicerModePeak == f_pl->cfg.mode)) {
                    continue;
                }

                /* Even index reserved for peak meters */
                if ((0 == (idx % 2)) && 
                    (bcmPolicerModeCommitted == f_pl->cfg.mode)) {
                    continue;
                }

                _FP_METER_BMP_ADD(fs->meter_bmp, idx);
                f_pl->pool_index =  fs->slice_number;
                f_pl->hw_index   =  idx /2;
                break;
            }
        } else 
#endif
        {
            if (0 == _FP_METER_BMP_TEST(fs->meter_bmp, idx)) {
                    _FP_METER_BMP_ADD(fs->meter_bmp, idx);
                f_pl->pool_index =  fs->slice_number;
                f_pl->hw_index   =  idx;
                break;
            }
        }
    }
    if (idx == fs->meters_count) {
        return (BCM_E_RESOURCE);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_meter_hw_free
 *
 * Purpose:
 *     Deallocate a policer from an entry slice.
 * 
 * Parameters:
 *     unit      - (IN) BCM device number.  
 *     f_ent     - (IN/OUT) Entry policer belongs to.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_meter_hw_free(int unit, _field_entry_t *f_ent) 
{
    _field_stage_t         *stage_fc;    /* Field stage control.            */
    _field_entry_policer_t *f_ent_pl;    /* Field entry policer structure.  */
    uint8                  entry_part;   /* Secondary entry part.           */
    _field_policer_t       *f_pl;        /* Policer descriptor.             */
    _field_group_t         *fg;          /* Field group structure.          */
    int                     rv;          /* Operation return status.        */

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    f_ent_pl = f_ent->policer;
    fg = f_ent->group;

    /* Get stage control structure. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Reject unused policers. */
    if (0 == (f_ent_pl->flags & _FP_POLICER_VALID)) {
        return (BCM_E_PARAM);
    }

    /* Read policer configuration.*/
    BCM_IF_ERROR_RETURN(_bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl));

    /* Policer slice index sanity check. */
    if (f_pl->pool_index >= stage_fc->tcam_slices) {
        return (BCM_E_INTERNAL);
    }

    /* Free policer id. */
    rv = _field_slice_meter_free(unit, f_ent, f_pl);

    /* Reset entry policer related flags. */
    if (f_ent->flags & _FP_ENTRY_POLICER_IN_SECONDARY_SLICE) {
        /* Get primary entry from the second slice. */
        rv = _bcm_field_entry_flags_to_tcam_part (_FP_ENTRY_SECONDARY, 
                                                  fg->flags, &entry_part);
        BCM_IF_ERROR_RETURN(rv);
        sal_memset(f_ent[entry_part].policer, 0, sizeof(_field_entry_policer_t));
        f_ent->flags &=  ~_FP_ENTRY_POLICER_IN_SECONDARY_SLICE;
    }
    return (rv);
}

/*
 * Function:
 *     _field_meter_hw_alloc
 *
 * Purpose:
 *     Allocate a policer/s for an entry from a slice.
 * 
 * Parameters:
 *     unit      - (IN) BCM device number.  
 *     f_ent     - (IN/OUT) Entry array policer belongs to.
 *     fs        - (IN) Desired slice for the policer.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_meter_hw_alloc(int unit, _field_entry_t *f_ent, _field_slice_t *fs) 
{
    _field_entry_policer_t *f_ent_pl;           /* Field entry policer .     */
    _field_policer_t       *f_pl;               /* Policer descriptor.       */
    _field_group_t         *fg;                 /* Field group structure.    */ 
    uint8                  entry_part;          /* Field entry tcam part .   */
    int                    rv = BCM_E_RESOURCE; /* Operation return status.  */

    /* Input parameters check. */
    if ((NULL == f_ent) || (NULL == fs)) {
        return (BCM_E_PARAM);
    }

    f_ent_pl = f_ent->policer;

    /* Reject unused policers. */
    if (0 == (f_ent_pl->flags & _FP_POLICER_VALID)) {
        return (BCM_E_PARAM);
    }

    /* Read policer configuration. */
    BCM_IF_ERROR_RETURN(_bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl));

    /*
     *  Allocate meter from a primary slice unless color dependent counter 
     *  is only availabe in secondary slice 
     */ 
    if (0 == (f_ent->flags & _FP_ENTRY_ALLOC_FROM_SECONDARY_SLICE)) {
        rv = _field_slice_meter_alloc(unit, fs, f_pl);
    }
    if (BCM_E_RESOURCE == rv)  {
        fg = f_ent->group;
        /* Double/Triple wide groups might allocate from secondary slice. */
        if ((fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) ||
            (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE)) {
            rv = _field_slice_meter_alloc(unit, fs + 1, f_pl);
            if (BCM_SUCCESS(rv)) {
                /* Get primary entry from the second slice. */
                rv = _bcm_field_entry_flags_to_tcam_part (_FP_ENTRY_SECONDARY, 
                                                          fg->flags, &entry_part);
                BCM_IF_ERROR_RETURN(rv);
                f_ent->flags |= _FP_ENTRY_POLICER_IN_SECONDARY_SLICE;
                sal_memcpy(f_ent[entry_part].policer, f_ent->policer, 
                           sizeof(_field_entry_policer_t));
                f_ent[entry_part].policer->flags |= _FP_POLICER_INSTALLED;
            }
        }
    }
    return (rv);
}


/*
 * Function:
 *     _field_policer_hw_free
 *
 * Purpose:
 *     Deallocate hw policer from an entry.
 * 
 * Parameters:
 *     unit      - (IN) BCM device number.  
 *     level     - (IN) Policer level.
 *     f_ent     - (IN) Entry policer belongs to.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_policer_hw_free (int unit, uint8 level, _field_entry_t *f_ent)
{
    _field_entry_policer_t *f_ent_pl;  /* Field entry policer structure. */
    _field_stage_t         *stage_fc;  /* Stage field contol.            */
    _field_policer_t       *f_pl;      /* Policer descriptor.            */

    /* Input parameters check. */
    if ((NULL == f_ent) || (level >= _FP_POLICER_LEVEL_COUNT)) {
        return (BCM_E_PARAM);
    }

    f_ent_pl = f_ent->policer + level;
    /* Skip uninstalled policers. */
    if (0 == (f_ent_pl->flags & _FP_POLICER_INSTALLED)) {
        return (BCM_E_NONE);
    }

    /* Read policer configuration.*/
    BCM_IF_ERROR_RETURN(_bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl));

    /* Decrement hw reference count. */
    if (f_pl->hw_ref_count > 0) {
        f_pl->hw_ref_count--; 
    }

    /* Policer not used by any other entry. */
    if (f_pl->hw_ref_count == 0) {
        /* Deinstall policer from hw. */
        BCM_IF_ERROR_RETURN
            (_field_stage_control_get(unit, f_ent->group->stage_id, &stage_fc));

        /* Mark hw resource as unused in sw. */
        if (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS) {
            BCM_IF_ERROR_RETURN 
                (_field_meter_pool_entry_free(unit, stage_fc, f_pl));
        } else {
            BCM_IF_ERROR_RETURN (_field_meter_hw_free (unit, f_ent));
        }
        /* Mark policer for reinstallation. */
        BCM_IF_ERROR_RETURN (_field_policer_hw_flags_set(unit, f_pl, 0));
    }
    f_ent_pl->flags &= ~_FP_POLICER_INSTALLED;
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_policers_hw_alloc 
 *
 * Purpose:
 *     Allocate policers required for entry installation.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry array.
 * Returns:
 *     BCM_E_XXX
 * Notes:
 */
STATIC int
_field_policers_hw_alloc(int unit, _field_entry_t *f_ent)
{
    _field_entry_policer_t *f_ent_pl;  /* Field entry policer structure.*/
    _field_stage_t         *stage_fc;  /* Stage field control.          */
    _field_policer_t       *f_pl;      /* Field policer descriptor.     */
    _field_control_t       *fc;        /* Field control structure.      */
    int                    idx;        /* Policer levels iterator.      */
    int                    rv;         /* Operation return status.      */
    _field_meter_pool_t    *f_mp;      /* Meter pool descriptor.        */

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    /* Get field stage control structure. */
    rv = _field_stage_control_get(unit, f_ent->group->stage_id, &stage_fc); 
    BCM_IF_ERROR_RETURN(rv);

    /* Allocate policers if necessary. */
    for (idx = 0; idx < _FP_POLICER_LEVEL_COUNT; idx++) {
        f_ent_pl = f_ent->policer + idx;
        /* Skip invalid policers. */
        if (0 == (f_ent_pl->flags & _FP_POLICER_VALID)) {
            continue;
        }
            
        /* Read policer configuration.*/
        rv = _bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl);
        BCM_IF_ERROR_RETURN(rv);

        /* 
         * Check if entry's primary slice_number matches 
         * Policer meter pool slice_id for Level0 policer.
         */
        if (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
            if ((0 == idx) && (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS)
                && (_FP_INVALID_INDEX != f_pl->pool_index)) {
                f_mp = stage_fc->meter_pool[f_pl->pool_index];
                if (f_ent->group->slices->slice_number != f_mp->slice_id) {
                    return (BCM_E_PARAM);
                }
            }
        }
        
        /* Check policer mode support - double check in case 
           attached policer was modified by bcm_policer_set API.
         */
        rv = _field_policer_mode_support(unit, f_ent, idx, f_pl);
        BCM_IF_ERROR_RETURN(rv);

        /* Allocate policer hw index. */
        if (_FP_INVALID_INDEX == f_pl->hw_index) {
            if (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS) {
                rv = _field_meterpool_hw_entry_alloc(unit, f_ent, f_pl);
            } else {
                rv = _field_meter_hw_alloc(unit, f_ent, f_ent->fs);
            }
            BCM_IF_ERROR_RETURN(rv);
        } 
        
        /* Increment hw reference count. */
        if (0 == (f_ent_pl->flags & _FP_POLICER_INSTALLED)) {
            f_ent_pl->flags |=  _FP_POLICER_INSTALLED;
            f_pl->hw_ref_count++;
        }

        if (f_pl->hw_flags & _FP_POLICER_DIRTY) {
            BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
            BCM_IF_ERROR_RETURN(fc->functions.fp_policer_install(unit, f_ent, f_pl));
        }
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_policers_hw_free
 *
 * Purpose:
 *     Free entry policers.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry descriptor.
 * Returns:
 *     BCM_E_XXX
 * Notes:
 */
STATIC int
_field_policers_hw_free(int unit, _field_entry_t *f_ent)
{
    _field_entry_policer_t *f_ent_pl;  /* Field entry policer structure.*/
    int                    idx;        /* Policer levels iterator.      */

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    /* Allocate policers if necessary. */
    for (idx = 0; idx < _FP_POLICER_LEVEL_COUNT; idx++) {
        f_ent_pl = f_ent->policer + idx;
        /* Skip invalid policers. */
        if (0 == (f_ent_pl->flags & _FP_POLICER_VALID)) {
            continue;
        }
        /* Skip installed policers. */
        if (0 == (f_ent_pl->flags & _FP_POLICER_INSTALLED)) {
            continue;
        }

        BCM_IF_ERROR_RETURN (_field_policer_hw_free (unit, idx, f_ent));
    }
    return (BCM_E_NONE);
}


/*
 * Function:
 *      _field_entry_policer_detach
 * Purpose:
 *      Detach a policer from a field entry.
 * Parameters:
 *      unit     - (IN) Unit number.
 *      entry_id - (IN) Field entry ID.
 *      level    - (IN) Policer level.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
STATIC int 
_field_entry_policer_detach(int unit, _field_entry_t *f_ent, int level)
{
    _field_policer_t       *f_pl;    /* Internal policer descriptor.  */
    _field_entry_policer_t *f_ent_pl;/* Field entry policer structure.*/
#if defined(BCM_KATANA_SUPPORT)
     int rv=0;
     vfp_policy_table_entry_t vfp_entry;
#endif
    /* Input parameters check. */
    if ((level >= _FP_POLICER_LEVEL_COUNT) || (level < 0)) {
        return (BCM_E_PARAM);
    }
#if defined(BCM_KATANA_SUPPORT)
    if (SOC_IS_KATANA(unit)) {
        if (_BCM_FIELD_STAGE_LOOKUP == f_ent->group->stage_id) {
            rv = _bcm_esw_delete_policer_from_table(unit, 
                   f_ent->global_meter_policer.pid, VFP_POLICY_TABLEm,0,&vfp_entry);
            if (BCM_FAILURE(rv)) {
                return (rv);
            }
            f_ent->global_meter_policer.pid = 0;
            f_ent->global_meter_policer.flags = 0;
            /* Entry must be reinstalled for policer to take effect. */
            f_ent->flags  |= _FP_ENTRY_DIRTY;
            return (BCM_E_NONE);
        }
    }
#endif

    /* Make sure policer attached to the entry. */
    f_ent_pl = f_ent->policer + level;
    if (0 == (f_ent_pl->flags & _FP_POLICER_VALID)) {
        return (BCM_E_EMPTY);
    }

    /* Get policer description structure. */
    BCM_IF_ERROR_RETURN(_bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl));

    /* If entry was installed decrement hw reference counter. */
    BCM_IF_ERROR_RETURN(_field_policer_hw_free (unit, level, f_ent));

    /* Decrement policer reference counter. */
    f_pl->sw_ref_count--;
   
    /* If no one else is using the policer and  
     * policer is internal destroy it. 
     */
    if ((1 == f_pl->sw_ref_count) && (f_pl->hw_flags & _FP_POLICER_INTERNAL)) {
        BCM_IF_ERROR_RETURN(_field_policer_destroy(unit, f_ent_pl->pid));
    }

    /* Detach policer from an entry. */
    f_ent_pl->pid   = _FP_INVALID_INDEX;
    f_ent_pl->flags = 0;

    /* Mark entry for reinstall. */
    f_ent->flags |= _FP_ENTRY_DIRTY;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_stat_get
 * Purpose:
 *     Lookup a statistics entity description structure by stat id.
 * Parmeters:
 *     unit      - (IN)  BCM device number. 
 *     sid       - (IN)  Statistics entity id. 
 *     stat_p    - (OUT) Lookup result.  
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_stat_get(int unit, int sid, _field_stat_t **stat_p)
{
    _field_stat_t    *f_st; /* Policer lookup pointer.  */
    _field_control_t *fc;   /* Field control structure. */
    uint32 hash_index;      /* Entry hash.              */

    /* Input parameters check. */
    if (NULL == stat_p) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    hash_index = sid & _FP_HASH_INDEX_MASK(fc);
    f_st  =  fc->stat_hash[hash_index];
    while (NULL != f_st) {
        /* Match entry id. */
        if (f_st->sid == sid) {
            *stat_p = f_st;
            return (BCM_E_NONE);
        }
        f_st = f_st->next;
    }

    /* Statistics entity with sid == sid was not found. */
    return (BCM_E_NOT_FOUND);
}

/*
 * Function:
 *      _field_stat_id_alloc
 * Purpose:
 *      Allocate a statistics entity id.
 * Parameters:
 *      unit    - (IN) BCM device number.
 *      sid     - (OUT) Stat id.  
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_field_stat_id_alloc(int unit, int *sid)
{
    int               max_count;           /* Maximum number of sids to try.*/
    _field_stat_t     *f_st;               /* Field stat descriptor.        */
    int               rv;                  /* Operation return status.      */ 
    static uint32  last_allocated_sid = 0; /* Policer id alloc tracker.     */ 
    
    /* Input parameters check. */
    if (NULL == sid) {
        return (BCM_E_PARAM);
    }

    max_count = _FP_ID_MAX;
    while (max_count--) {
        last_allocated_sid++;
        if (_FP_ID_MAX == last_allocated_sid) {
            last_allocated_sid = _FP_ID_BASE;
        }
        rv = _bcm_field_stat_get(unit, last_allocated_sid, &f_st);
        if (BCM_E_NOT_FOUND == rv) {
            *sid = last_allocated_sid;
            return (BCM_E_NONE);
        }
        if (BCM_FAILURE(rv)) {
            return (rv);
        }
    }
    return (BCM_E_RESOURCE);
}


/*
 * Function: 
 *    _field_stat_array_to_bmap
 *
 * Description:
 *      API caller statistics array bit map
 * Parameters:
 *      unit  - (IN) BCM device number.
 *      f_st  - (IN) Field statistics entity.
 *      bmap  - (OUT) Field group id.
 * Returns:
 *      BCM_E_XXX
 */
STATIC int 
_field_stat_array_to_bmap(int unit, _field_stat_t *f_st, uint32 *bmap)
{
    int idx;

    /* Input parameters check */
    if ((NULL == f_st) || (NULL == bmap)) {
        return (BCM_E_PARAM); 
    }

    *bmap = 0;
    for (idx = 0; idx < f_st->nstat; idx++) {
        if (NULL == (f_st->stat_arr + idx)) {
            return (BCM_E_PARAM);
        }

        if ((int)f_st->stat_arr[idx] > _bcmFieldStatCount) {
            return (BCM_E_PARAM);
        }

        *bmap |= (1 << (int)f_st->stat_arr[idx]);
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *   _field_stat_hw_mode_to_bmap 
 *
 * Description:
 *      HW counter mode to statistics bitmap. 
 * Parameters:
 *      unit           - (IN) BCM device number.
 *      mode           - (IN) HW counter mode.
 *      stage_id       - (IN) Stage id.
 *      hw_bmap        - (OUT) Statistics bitmap. 
 *      hw_entry_count - (OUT) Number of counters required.
 * Returns:
 *      BCM_E_XXX
 */
STATIC int 
_field_stat_hw_mode_to_bmap(int unit, uint8 mode, 
                            _field_stage_id_t stage_id, 
                            uint32 *hw_bmap, uint8 *hw_entry_count)
{
    int rv;

    /* Input parameters check. */
    if ((NULL == hw_bmap) || (NULL == hw_entry_count)) {
        return (BCM_E_PARAM);
    }
#if defined(BCM_TRIDENT_SUPPORT)
    if ((SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) &&
        (stage_id == _BCM_FIELD_STAGE_INGRESS)) {
        rv = _bcm_field_trident_stat_hw_mode_to_bmap(unit, mode, stage_id,
                                                 hw_bmap, hw_entry_count);
    } else 
#endif /* BCM_TRIDENT_SUPPORT */
#if defined(BCM_TRX_SUPPORT)
    if (SOC_IS_TRX(unit)) {
        rv = _bcm_field_trx_stat_hw_mode_to_bmap(unit, mode, stage_id,
                                                 hw_bmap, hw_entry_count);
    } else 
#endif /* BCM_TRX_SUPPORT */
    {
        rv = _bcm_field_fb_stat_hw_mode_to_bmap(unit, mode, stage_id, 
                                                hw_bmap, hw_entry_count);
    }
    return (rv);
}

/*
 * Function: 
 *    _field_stat_hw_mode_get
 *
 * Description:
 *      Get hw counter mode which will satisfy requested statistics set.
 * Parameters:
 *      unit     - (IN) BCM device number.
 *      f_st     - (IN) Field statistics entity.
 *      stage_id - (IN) Field stage id.
 * Returns:
 *      BCM_E_XXX
 */
STATIC int 
_field_stat_hw_mode_get(int unit, _field_stat_t *f_st,
                        _field_stage_id_t stage_id)
{
    uint32            req_bmap;       /* Requested statistics bitmap.    */
    uint32            hw_bmap;        /* HW supported statistics bitmap. */
    uint8             hw_entry_count; /* Number of counter table entries.*/
    uint8             idx;            /* HW counter modes iterator.      */
    int               rv;             /* Operation return status.        */
    int               fp_stat_hw_mode_max = _FP_STAT_HW_MODE_MAX;
    int               val;

    /* Input parameters check. */
    if (NULL == f_st) {
        return (BCM_E_PARAM);
    }

    if ((SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) &&
        (stage_id == _BCM_FIELD_STAGE_INGRESS)) {
        fp_stat_hw_mode_max = _FP_TRIDENT_STAT_HW_MODE_MAX;
    }
    /* Get application requested bitmap. */
    rv = _field_stat_array_to_bmap (unit, f_st, &req_bmap);
    BCM_IF_ERROR_RETURN(rv);

    /* If bitmap is zero - no mode selection is required. */
    if (0 == req_bmap) {
        f_st->hw_stat = 0;
        f_st->hw_entry_count = 0;
        f_st->hw_mode = 0;
        return (BCM_E_NONE);
    }

#if defined(BCM_TRIUMPH2_SUPPORT)
    if ((soc_feature(unit, soc_feature_field_vfp_flex_counter)) &&
        (_BCM_FIELD_STAGE_LOOKUP == stage_id)) {
        hw_bmap = (1 << (int)bcmFieldStatBytes) | \
            (1 << (int)bcmFieldStatPackets);
            if (0 == ((req_bmap | hw_bmap) & ~(hw_bmap))) {
                f_st->hw_mode = 1;
                f_st->hw_stat = hw_bmap;
                f_st->hw_entry_count = 1;
                return (BCM_E_NONE);
            }
        return (BCM_E_UNAVAIL);
    }
#endif /* BCM_TRIUMPH2_SUPPORT */

    /* Always use counter pair for bcm_field_counter_xxx APIs. */
    if (f_st->hw_flags & _FP_STAT_COUNTER_PAIR) {
        val = f_st->stat_arr[0];
        if ((SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) &&
            (stage_id == _BCM_FIELD_STAGE_INGRESS)) {
            switch(val) {
                case (_bcmFieldStatBytesOdd):
                case (_bcmFieldStatPacketsOdd):
                    f_st->hw_stat |= ((1 << (int)_bcmFieldStatPacketsOdd) |
                                      (1 << (int)_bcmFieldStatBytesOdd));
                    f_st->hw_mode = (0x7 << 3);
                    break;
                case (_bcmFieldStatBytesEven):
                case (_bcmFieldStatPacketsEven):
                default:
                    f_st->hw_mode = 0x7;
                    f_st->hw_stat |= ((1 << (int)_bcmFieldStatPacketsEven) |
                                      (1 << (int)_bcmFieldStatBytesEven));
                    break;
            }
        } else if (SOC_IS_TRX(unit)) {
            f_st->hw_mode = 1;
            f_st->hw_stat |= ((1 << (int)_bcmFieldStatPacketsEven) |
                              (1 << (int)_bcmFieldStatPacketsOdd) |
                              (1 << (int)_bcmFieldStatBytesEven) |
                              (1 << (int)_bcmFieldStatBytesOdd));
        } else if (val == _bcmFieldStatBytesEven) {
            f_st->hw_mode = 0x9;
            f_st->hw_stat |= (1 << (int)_bcmFieldStatBytesEven);
        } else if (val == _bcmFieldStatBytesOdd) {
            f_st->hw_mode = 0xa;
            f_st->hw_stat |= (1 << (int)_bcmFieldStatBytesOdd);
        } else if (val == _bcmFieldStatPacketsEven) {
            f_st->hw_mode = 0x1;
            f_st->hw_stat |= (1 << (int)_bcmFieldStatPacketsEven);
        } else {
            f_st->hw_mode = 0x2;
            f_st->hw_stat |= (1 << (int)_bcmFieldStatPacketsOdd);
        }
        f_st->hw_entry_count = 2;
        return (BCM_E_NONE);
    }

    /* Check if any hw supported mode will produce requested statistics. */
#ifdef BCM_WARM_BOOT_SUPPORT
    if (SOC_WARM_BOOT(unit)) {
        /* The f_st->hw_mode has already been read from the HW */
        rv = _field_stat_hw_mode_to_bmap (unit, f_st->hw_mode, stage_id, 
                                          &hw_bmap, &hw_entry_count);
    } else 
#endif
    {
        for (idx = 1; idx <= fp_stat_hw_mode_max; idx++) { 
            rv = _field_stat_hw_mode_to_bmap (unit, idx, stage_id, 
                                              &hw_bmap, &hw_entry_count);
            if (0 == ((req_bmap | hw_bmap) & ~(hw_bmap))) {
                break;
            }
        }
        if  (idx > fp_stat_hw_mode_max) {
            return (BCM_E_RESOURCE);
        }
        f_st->hw_mode = idx;
    }

    f_st->hw_stat = hw_bmap;
    f_st->hw_entry_count = hw_entry_count;

    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_stat_destroy2
 * Purpose:
 *      Deinitialize a statistics collection entity
 * Parameters:
 *      unit    - (IN) Unit number.
 *      fc      - (IN) Internal stat entity descriptor.
 *      f_st    - (IN) Field stat s
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_field_stat_destroy2(int unit, _field_control_t *fc, _field_stat_t *f_st)
{
    /* Input parameters check. */
    if ((NULL == fc) || (NULL == f_st)) {
        return (BCM_E_PARAM);
    }

    /* Reject destroy if policer is in use. */ 
    if (f_st->sw_ref_count > 1) {
        return (BCM_E_BUSY);
    }

    /* Remove policer for lookup hash. */
    _FP_HASH_REMOVE(fc->stat_hash, _field_stat_t, f_st,
                    (f_st->sid & _FP_HASH_INDEX_MASK(fc)));

    /* De-allocate statistics entity descriptor. */
    if (NULL != f_st->stat_arr) {
        sal_free(f_st->stat_arr);
    }
    if (NULL != f_st->stat_values) {
        sal_free(f_st->stat_values);
    }
    sal_free(f_st);

    /* Decrement number of active policers. */
    if (fc->stat_count > 0) {
        fc->stat_count--;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_stat_destroy
 * Purpose:
 *      Deinitialize a statistics collection entity
 * Parameters:
 *      unit    - (IN) Unit number.
 *      sid     - (IN) Statistics entity id.  
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_field_stat_destroy(int unit, int sid)
{
    _field_control_t  *fc;         /* Field control structure.     */
    _field_stat_t     *f_st;       /* Internal policer descriptor. */
    int               rv;          /* Operation return status.     */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Find policer info. */
    rv = _bcm_field_stat_get(unit, sid, &f_st);
    BCM_IF_ERROR_RETURN(rv);

    return _field_stat_destroy2(unit, fc, f_st);
}

/*
 * Function:
 *      _field_stat_destroy_all
 * Purpose:
 *      Destroy all statistics collection entities
 * Parameters:
 *      unit    - (IN) Unit number.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_field_stat_destroy_all(int unit)
{
    _field_control_t *fc;   /* Field control structure. */
    int idx;                /* Entry hash iterator.     */
    int idx_max;            /* Index max.               */          
    int rv;                 /* Operation return status. */
    
    rv = _field_control_get(unit, &fc);
    BCM_IF_ERROR_RETURN(rv);

    idx_max = _FP_HASH_SZ(fc);
    for (idx= 0; idx < idx_max; idx ++) {
        while (NULL != fc->stat_hash[idx]) {
            rv = _field_stat_destroy2(unit, fc, fc->stat_hash[idx]);
            if (BCM_FAILURE(rv)) {
                break;
            }
        }
    }
    return (rv);
}

/*
 * Function: 
 *    _field_stat_array_init
 *
 * Description:
 *      Preserve API requested statistics array.
 * Parameters:
 *      unit     - (IN) BCM device number.
 *      f_st     - (IN) Field statistics entity. 
 *      nstat    - (IN) Number of elements in stat array.
 *      stat_arr - (IN) Collected statistics descriptors array.
 * Returns:
 *      BCM_E_XXX
 */
int 
_field_stat_array_init(int unit, _field_stat_t *f_st, 
                       int nstat, bcm_field_stat_t *stat_arr) 
{
    int rv; 

    /* Input parameters check. */
    if ((NULL == f_st) || (0 == nstat) || (NULL == stat_arr)) {
        return (BCM_E_PARAM);
    }

    /* Free currently allocated  stat array if any. */ 
    if (NULL != f_st->stat_arr) {
        sal_free(f_st->stat_arr);
        f_st->stat_arr = NULL;
        f_st->nstat = 0;
    }

    /* Free currently allocated  values array if any. */ 
    if (NULL != f_st->stat_values) {
        sal_free(f_st->stat_values);
        f_st->stat_values = NULL;
    }

    _FP_XGS3_ALLOC(f_st->stat_arr, (nstat * sizeof (bcm_field_stat_t)),
                   "Field stat array");
    if (NULL == f_st->stat_arr) {
        return (BCM_E_MEMORY);
    }

    _FP_XGS3_ALLOC(f_st->stat_values, (nstat * sizeof (uint64)),
                   "Field stat values array");
    if (NULL == f_st->stat_values) {
        sal_free(f_st->stat_arr);
        f_st->stat_arr = NULL;
        return (BCM_E_MEMORY);
    }

    /* Copy stats array. */
    sal_memcpy(f_st->stat_arr, stat_arr, (nstat * sizeof(bcm_field_stat_t)));
    f_st->nstat = nstat;

    /* Map stats array to hw mode. */
    rv = _field_stat_hw_mode_get(unit, f_st, f_st->stage_id);
    if (BCM_FAILURE(rv)) {
        sal_free(f_st->stat_arr);
        sal_free(f_st->stat_values);
        f_st->stat_arr = NULL;
        f_st->stat_values = NULL;
        return (rv);
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *    _field_stat_create
 *
 * Description:
 *       Create statistics collection entity.
 * Parameters:
 *      unit     - (IN) BCM device number.
 *      group    - (IN) Field group id. 
 *      nstat    - (IN) Number of elements in stat array.
 *      stat_arr - (IN) Collected statistics descriptors array.
 *      flags    - (IN) HW/API specific flags. 
 *      stat_id  - (OUT) Statistics entity id.
 * Returns:
 *      BCM_E_XXX
 */
STATIC int 
_field_stat_create(int unit, bcm_field_group_t group, int nstat, 
                   bcm_field_stat_t *stat_arr, uint32 flags, int *stat_id) 
{
    _field_control_t    *fc;          /* Field control structure.     */
    _field_group_t      *fg;          /* Field group pointer.         */
    int                 rv;           /* Operation return status.     */
    _field_stat_t       *f_st = NULL; /* Internal stat descriptor.    */

    /* Input parameters check. */
    if ((nstat < 0) || (NULL == stat_id) || (nstat > _bcmFieldStatCount)) {
        return (BCM_E_PARAM);
    }
    if ((0 != nstat) && (NULL == stat_arr)) {
        return (BCM_E_PARAM);
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN (_field_control_get(unit, &fc));

    /* Get group descriptor. */
    rv = _field_group_get (unit, group, &fg);
    BCM_IF_ERROR_RETURN(rv);

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
   if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
    if ((0 == soc_feature(unit, soc_feature_field_vfp_flex_counter)) && 
        (_BCM_FIELD_STAGE_LOOKUP == fg->stage_id)) {
        return (BCM_E_UNAVAIL);
    }
   }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */


    if (flags & _FP_STAT_CREATE_ID) {
        /* Check if statistics entity id already exists. */
        rv = _bcm_field_stat_get(unit, *stat_id, &f_st);
        if (BCM_SUCCESS(rv)) {
            /* Stat ID already exists return */
            return (BCM_E_EXISTS);
        }
        flags = 0;
    } else {
        /* Generate statistics entity id. */
        BCM_IF_ERROR_RETURN (_field_stat_id_alloc(unit, stat_id));
    }

    /* Allocate statistics descriptor. */
    _FP_XGS3_ALLOC(f_st, sizeof (_field_stat_t), "Field stat entity");
    if (NULL == f_st) {
        return (BCM_E_MEMORY);
    }

    /* Initialize reference count to 1. */
    f_st->sw_ref_count = 1;

    /* Set hw index to - no hw resources allocated. */
    f_st->pool_index = _FP_INVALID_INDEX;
    f_st->hw_index = _FP_INVALID_INDEX;

    /* Initialize stat id. */
    f_st->sid = *stat_id;

    /* Store caller internal flags. */
    f_st->hw_flags = flags;
    f_st->stage_id = fg->stage_id;
    f_st->gid      = fg->gid;

    /* Allocate counters array. */
    if (0 != nstat) {
        rv = _field_stat_array_init(unit, f_st, nstat, stat_arr);
        if (BCM_FAILURE(rv)) {
            sal_free(f_st);
            return (rv);
        }
    }

    /* Insert policer into statistics hash. */
    _FP_HASH_INSERT(fc->stat_hash, f_st, (*stat_id & _FP_HASH_INDEX_MASK(fc)));

    /* Increment number of active policers. */
    fc->stat_count++;
    return (BCM_E_NONE);
}

/*
 * Function: 
 *    _field_entry_stat_attach
 *
 * Description:
 *       Attach statistics entity to Field Processor entry.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      entry     - (IN) Field entry id. 
 *      stat_id   - (IN) Statistics entity id.
 * Returns:
 *      BCM_E_XXX
 */
STATIC int 
_field_entry_stat_attach(int unit, _field_entry_t *f_ent, int stat_id)
{
    _field_entry_stat_t    *f_ent_st; /* Field entry statistics structure.*/
    _field_stat_t          *f_st;     /* Internal statisics descriptor.   */
    _field_stage_id_t      stage_id;  /* Pipeline stage id.               */
    int                    rv;        /* Operation return status.         */
    _field_stage_t         *stage_fc; /* Field stage control structure.*/

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    /* Get entry pipeline stage id. */
    stage_id = f_ent->group->stage_id;

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
   if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
    if ((0 == soc_feature(unit, soc_feature_field_vfp_flex_counter)) && 
        (_BCM_FIELD_STAGE_LOOKUP == stage_id)) {
        return (BCM_E_UNAVAIL);
    }
   }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */

    /* Check if another  statistics entity is already attached. */
    f_ent_st = &f_ent->statistic;
    if (f_ent_st->flags & _FP_ENTRY_STAT_VALID) {
        return (BCM_E_EXISTS);
    }

    /* Get statistics entity  description structure. */
    rv = _bcm_field_stat_get(unit, stat_id, &f_st);
    BCM_IF_ERROR_RETURN(rv);

    if ((f_st->stage_id != stage_id) || 
        (f_st->gid !=  f_ent->group->gid)) {
        return (BCM_E_PARAM);
    }

    /* Get stage control information. */
    BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, stage_id, &stage_fc));

    /* Check if entry and stat are referencing same physical slice */
    if (_BCM_FIELD_STAGE_INGRESS == stage_id) {
        if ((0 == (stage_fc->flags & _FP_STAGE_GLOBAL_COUNTERS))
            && _FP_INVALID_INDEX != f_st->hw_index) {
            if (f_ent->fs->slice_number != f_st->pool_index) {
                FP_ERR(("FP(unit %d) Error: Entry:%d belongs to an expanded group.\n",
                    unit, f_ent->eid));
                FP_ERR(("Create a new Stat and attach to Entry. "));
                FP_ERR(("Counters are per-slice resource.\n"));
                return (BCM_E_CONFIG);
            }
        }
    }

    /* Check if statistics entity can be shared. */
    if (f_st->sw_ref_count > 1) {
        /* Statistics sharing is restricted to a single stage. */ 
        if (stage_id != f_st->stage_id) {
            return (BCM_E_PARAM);
        }
    }

    /* Increment statistics entity reference counter. */
    f_st->sw_ref_count++;

    /* Attach statistics entity to an entry. */
    f_ent_st->flags |= _FP_ENTRY_STAT_VALID;
    f_ent_st->sid    = stat_id;

    /* 
     * If qualifiers have not been modified for this entry,
     * set Action only dirty flag.
     */
    if (0 == (f_ent->flags & _FP_ENTRY_DIRTY)) {
        f_ent->flags |= _FP_ENTRY_ACTION_ONLY_DIRTY;
    }

    /* Entry must be reinstalled for statistics to take effect. */
    f_ent->flags  |= _FP_ENTRY_DIRTY;

    /* Increment group counters count. */ 
    f_ent->group->group_status.counter_count++;
    return (BCM_E_NONE);
}

#if defined(BCM_TRIUMPH2_SUPPORT)
/*
 * Function:
 *     _bcm_esw_fp_flex_stat_index_set
 *
 * Purpose:
 *     Allocation callback from flex stat module used to notify fp module 
 *     allocated flex stat index.
 * Parameters:
 *     unit      - (IN) BCM device number.  
 *     stage_fc  - (IN) Stage field control structure. 
 *     f_ent     - (IN/OUT) Entry array policer belongs to.
 *     fs        - (IN) Desired slice for the counter.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_bcm_esw_fp_flex_stat_index_set(int unit, _bcm_flex_stat_handle_t handle,
                                int fs_idx, void *cookie)
{
    _field_stat_t *f_st = (_field_stat_t *)cookie;
    f_st->hw_index = fs_idx;
    return (BCM_E_NONE);
}
#endif /* BCM_TRIUMPH2_SUPPORT */

/*
 * Function:
 *     _field_slice_counter_free
 *
 * Purpose:
 *     Free a counter from a slice.
 * 
 * Parameters:
 *     unit  - (IN) Bcm device number.
 *     f_ent - (IN) Field entry.
 *     f_st  - (IN) Statistics entity.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_slice_counter_free(int unit, _field_entry_t *f_ent, _field_stat_t *f_st)
{
    uint8          entry_part;   /* Secondary slice entry part.    */
    _field_group_t *fg;          /* Field group structure.         */
    _field_slice_t *fs;          /* Field slice structure.         */
    int            idx;          /* SW counter index.              */
    int            rv = BCM_E_NONE; /* Operation return status.    */

    if ((NULL == f_ent) || (NULL == f_st)) {
        return (BCM_E_PARAM);
    }

    fg = f_ent->group;
    fs = (f_ent->flags & _FP_ENTRY_STAT_IN_SECONDARY_SLICE) ? \
         f_ent->fs + 1: f_ent->fs;

#if defined (BCM_TRIUMPH2_SUPPORT)
    /* Free is  external for vfp counters. */
    if (_BCM_FIELD_STAGE_LOOKUP == fg->stage_id) {
       if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
        rv = _bcm_esw_flex_stat_enable_set(unit, _bcmFlexStatTypeFp,
                                             _bcm_esw_fp_flex_stat_index_set,
                                              (void *)f_st, f_st->sid, FALSE);
       }
        f_st->hw_index   = _FP_INVALID_INDEX;
        f_st->pool_index = _FP_INVALID_INDEX;
        /* During system restart flex stat module 
         * might be reinitialized before fp reinit. Hence
         * calls to the flex stat module will result in BCM_E_NOT_FOUND 
         * error code.
         */
        if ((_BCM_FIELD_STAGE_LOOKUP == f_st->stage_id) &&
            (BCM_E_NOT_FOUND == rv)) {
            rv = BCM_E_NONE;
        }
        return (rv);
    }
#endif /* BCM_TRIUMPH2_SUPPORT */

#if defined (BCM_FIREBOLT2_SUPPORT)
    if (SOC_IS_FIREBOLT2(unit) && (_BCM_FIELD_STAGE_EGRESS == f_st->stage_id)) {
        /* FB2 - doesn't have counter pairs in stage egress. */
        idx = f_st->hw_index;
    } else 
#endif /* BCM_FIREBOLT2_SUPPORT */
    {
        idx = 2 * f_st->hw_index;
    }

    /* Clear counter is used bit. */
    if (2 == f_st->hw_entry_count) {
        _FP_COUNTER_BMP_REMOVE(fs->counter_bmp, idx);
        _FP_COUNTER_BMP_REMOVE(fs->counter_bmp, idx + 1);
    } else if (0 == (f_st->hw_mode % 2)) {
        _FP_COUNTER_BMP_REMOVE(fs->counter_bmp, idx + 1);
    } else {
        _FP_COUNTER_BMP_REMOVE(fs->counter_bmp, idx);
    }

    /* Reset entry policer related flags. */
    if (f_ent->flags & _FP_ENTRY_STAT_IN_SECONDARY_SLICE) {
        /* Get primary entry from the second slice. */
        rv = _bcm_field_entry_flags_to_tcam_part (_FP_ENTRY_SECONDARY, 
                                                  fg->flags, &entry_part);
        BCM_IF_ERROR_RETURN(rv);
        sal_memset(&f_ent[entry_part].statistic, 0, sizeof(_field_entry_stat_t));
        f_ent->flags &=  ~_FP_ENTRY_STAT_IN_SECONDARY_SLICE;
    }

    f_st->hw_index   = _FP_INVALID_INDEX;
    f_st->pool_index = _FP_INVALID_INDEX;
    return BCM_E_NONE;
}

/*
 * Function:
 *    _field_sw_counter_set
 *
 * Description:
 *   Service routine used to set 64-bit software accumulated counters.
 * Parameters:
 *   unit         - (IN) BCM device number. 
 *   stage_fc     - (IN) Stage field control structure.
 *   idx          - (IN) Counter hw index. 
 *   packet_count - (OUT) Packet Counter value
 *   byte_count   - (OUT) Byte Counter value
 * Returns:
 *    BCM_E_XXX
 */
STATIC int
_field_sw_counter_set(int unit, _field_stage_t *stage_fc,
                      int idx, uint64 *packet_count,
                      uint64 *byte_count)
{
    _field_control_t          *fc;           /* Field control structure. */
    soc_mem_t                 counter_x_mem; /* Counter table on X pipe  */
    soc_mem_t                 counter_y_mem; /* Counter table on Y pipe  */
    uint32                    *hw_buf_x;     /* X memory HW buffer.      */ 
    uint32                    *hw_buf_y;     /* Y memory HW buffer.      */ 
    int                       rv;            /* Operation return status. */

    hw_buf_x = hw_buf_y = NULL;
    
    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Get counter memory. */
    rv = _field_counter_mem_get(unit, stage_fc, &counter_x_mem, &counter_y_mem);
    BCM_IF_ERROR_RETURN(rv);

    /* HW index sanity check. */
    if (idx < soc_mem_index_min(unit, counter_x_mem) ||
        idx > soc_mem_index_max(unit, counter_x_mem)) {
        return (BCM_E_INTERNAL);
    }

    /* Allocate buffer for counter values in HW.  */
    _FP_XGS3_ALLOC(hw_buf_x, 2 * WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS), 
                   "Counter buffers");
    if (NULL == hw_buf_x) {
        return (BCM_E_MEMORY);
    }

    /* Read X pipeline counter memory. */
    rv = soc_mem_read(unit, counter_x_mem, MEM_BLOCK_ANY, idx, hw_buf_x);
    if (BCM_FAILURE(rv)) {
        sal_free(hw_buf_x);
        return (BCM_E_MEMORY);
    }

    /* Read Y pipeline counter memory. */
    if (INVALIDm != counter_y_mem) {
        hw_buf_y = hw_buf_x + SOC_MAX_MEM_FIELD_WORDS;
        rv = soc_mem_read(unit, counter_y_mem, MEM_BLOCK_ANY, idx, hw_buf_y);
        if (BCM_FAILURE(rv)) {
            sal_free(hw_buf_x);
            return (BCM_E_MEMORY);
        }
    }

    /* Process accumulated counter value. */
    rv = fc->functions.fp_counter_set(unit, stage_fc, counter_x_mem,
                                      hw_buf_x, counter_y_mem, hw_buf_y,
                                      idx, packet_count, byte_count);
    sal_free(hw_buf_x);
    return (rv);
}

/*
 * Function:
 *    _field_sw_counter_get
 *
 * Description:
 *       Service routine used to retrieve 64-bit software accumulated counters.
 * Parameters:
 *   unit         - (IN) BCM device number. 
 *   stage_fc     - (IN) Stage field control structure.
 *   idx          - (IN) Counter hw index. 
 *   packet_count - (OUT) Packet Counter value
 *   byte_count   - (OUT) Byte Counter value
 * Returns:
 *    BCM_E_XXX
 */
STATIC int
_field_sw_counter_get(int unit, _field_stage_t *stage_fc,
                      int idx, uint64 *packet_count,
                      uint64 *byte_count)
{
    _field_control_t          *fc;           /* Field control structure. */
    soc_mem_t                 counter_x_mem; /* Counter table on X pipe  */
    soc_mem_t                 counter_y_mem; /* Counter table on Y pipe  */
    uint32                    *hw_buf_x;     /* X memory HW buffer.      */ 
    uint32                    *hw_buf_y;     /* Y memory HW buffer.      */ 
    int                       rv;            /* Operation return status. */

    COMPILER_64_ZERO(*packet_count);
    COMPILER_64_ZERO(*byte_count);
    hw_buf_x = hw_buf_y = NULL;
    
    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Get counter memory. */
    rv = _field_counter_mem_get(unit, stage_fc, &counter_x_mem, &counter_y_mem);
    BCM_IF_ERROR_RETURN(rv);

    /* HW index sanity check. */
    if (idx < soc_mem_index_min(unit, counter_x_mem) ||
        idx > soc_mem_index_max(unit, counter_x_mem)) {
        return (BCM_E_INTERNAL);
    }

    /* Allocate buffer for counter values in HW.  */
    _FP_XGS3_ALLOC(hw_buf_x, 2 * WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS), 
                   "Counter buffers");
    if (NULL == hw_buf_x) {
        return (BCM_E_MEMORY);
    }

    /* Read X pipeline counter memory. */
    if (INVALIDm != counter_x_mem) {
        rv = soc_mem_read(unit, counter_x_mem, MEM_BLOCK_ANY, idx, hw_buf_x);
        if (BCM_FAILURE(rv)) {
            sal_free(hw_buf_x);
            return (BCM_E_MEMORY);
        }
    }

    /* Read Y pipeline counter memory. */
    if (INVALIDm != counter_y_mem) {
        hw_buf_y = hw_buf_x + SOC_MAX_MEM_FIELD_WORDS;
        rv = soc_mem_read(unit, counter_y_mem, MEM_BLOCK_ANY, idx, hw_buf_y);
        if (BCM_FAILURE(rv)) {
            sal_free(hw_buf_x);
            return (BCM_E_MEMORY);
        }
    }

    /* Process accumulated counter value. */
    rv = fc->functions.fp_counter_get(unit, stage_fc, counter_x_mem,
                                      hw_buf_x, counter_y_mem, hw_buf_y,
                                      idx, packet_count, byte_count);
    sal_free(hw_buf_x);
    return (rv);
}


/*
 * Function:
 *      _field_stat_value_set
 *
 * Description:
 *      Set 64 bit counter value for specific statistic type.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      f_st      - (IN) Statistics entity descriptor.
 *      stat      - (IN) Collected statistics descriptor.
 *      value     - (IN) Collected counters value.
 * Returns:
 *      BCM_E_XXX
 */
int 
_field_stat_value_set(int unit, _field_stat_t *f_st, bcm_field_stat_t stat, 
                       uint64 value)
{
    _field_stage_t      *stage_fc;      /* Stage field control.         */
    _field_control_t    *fc;            /* Field control structure.     */
#if defined (BCM_TRIUMPH2_SUPPORT)
    _bcm_flex_stat_t    flex_stat;      /* Flex stat type.              */
#endif /* BCM_TRIUMPH2_SUPPORT */
    int                 idx1;           /* First counter index to read. */
    int                 idx2;           /* Second counter index to read.*/
    uint32              flags;          /* _FP_STAT_XXX.                */
    int                 rv;             /* Operation return status.     */

    /* Input parameters check. */
    if (NULL == f_st) {
        return (BCM_E_PARAM);
    }

#if defined (BCM_TRIUMPH2_SUPPORT)
    /* Flexible stat counters handling. */
    if (_BCM_FIELD_STAGE_LOOKUP == f_st->stage_id) {
        flex_stat = (stat == bcmFieldStatBytes) ? _bcmFlexStatIngressBytes :
            _bcmFlexStatIngressPackets; 
        return _bcm_esw_flex_stat_set(unit, _bcmFlexStatTypeFp,
                                      f_st->sid, flex_stat, value);
    }
#endif /* BCM_TRIUMPH2_SUPPORT */

    /* Get field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Stage field control structure. */
    rv = _field_stage_control_get(unit, f_st->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Check that stat was requested during statistics entity creation. */
    for (idx1 = 0; idx1 < f_st->nstat; idx1++) {
        if (stat == f_st->stat_arr[idx1]) {
            break;
        }
    }
    if (idx1 == f_st->nstat) {
        return (BCM_E_PARAM);
    }

    /* Get hw indexes and flags needed to compose requested statistic.*/
    rv = fc->functions.fp_stat_index_get(unit, f_st, stat, &idx1, 
                                         &idx2, &flags);
    BCM_IF_ERROR_RETURN(rv);

    /* Set accumulated counter value at primary index. */
    if (_FP_INVALID_INDEX == idx1) {
        return (BCM_E_INTERNAL);
    }

    if (flags & _FP_STAT_BYTES) {
        rv = _field_sw_counter_set(unit, stage_fc, idx1, NULL, &value);
    } else {
        rv = _field_sw_counter_set(unit, stage_fc, idx1, &value, NULL);
    }
    BCM_IF_ERROR_RETURN(rv);

    /* Reset accumulated counter value at secondary index. */
    if (_FP_INVALID_INDEX != idx2) {
        COMPILER_64_ZERO (value);
        if (flags & _FP_STAT_BYTES) {
            rv = _field_sw_counter_set(unit, stage_fc, idx2, NULL, &value);
        } else {
            rv = _field_sw_counter_set(unit, stage_fc, idx2, &value, NULL);
        }
    }
    return (rv);
}

/*
 * Function:
 *      _field_stat_value_get
 *
 * Description:
 *      Get 64 bit counter value for specific statistic type.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      f_st      - (IN) Statistics entity descriptor.
 *      stat      - (IN) Collected statistics descriptor.
 *      value     - (OUT) Collected counters value.
 * Returns:
 *      BCM_E_XXX
 */
int 
_field_stat_value_get(int unit, _field_stat_t *f_st, bcm_field_stat_t stat, 
                       uint64 *value)
{
    uint64              packet_count_1; /* Primary index packet count.  */
    uint64              byte_count_1;   /* Primary index byte count.    */
    uint64              packet_count_2; /* Secondary index packet count.*/
    uint64              byte_count_2;   /* Secondary index byte count.  */
    _field_stage_t      *stage_fc;      /* Stage field control.         */
#if defined (BCM_TRIUMPH2_SUPPORT)
    _bcm_flex_stat_t    flex_stat;      /* Flex stat type.              */
#endif /* BCM_TRIUMPH2_SUPPORT */
    _field_control_t    *fc;            /* Field control structure.     */
    int                 idx1;           /* First counter index to read. */
    int                 idx2;           /* Second counter index to read.*/
    uint32              flags;          /* _FP_STAT_XXX.                */
    int                 rv;             /* Operation return status.     */

    /* Input parameters check. */
    if ((NULL == value) || (NULL == f_st)) {
        return (BCM_E_PARAM);
    }

#if defined (BCM_TRIUMPH2_SUPPORT)
    /* Flexible stat counters handling. */
    if (_BCM_FIELD_STAGE_LOOKUP == f_st->stage_id) {
        flex_stat = (stat == bcmFieldStatBytes) ? _bcmFlexStatIngressBytes :
            _bcmFlexStatIngressPackets; 
        return _bcm_esw_flex_stat_get(unit, _bcmFlexStatTypeFp,
                                      f_st->sid, flex_stat, value);
    }
#endif /* BCM_TRIUMPH2_SUPPORT */

    /* Initialization. */
    COMPILER_64_ZERO(packet_count_1);
    COMPILER_64_ZERO(packet_count_2);
    COMPILER_64_ZERO(byte_count_1);
    COMPILER_64_ZERO(byte_count_2);
    idx1 = idx2 = _FP_INVALID_INDEX;
    flags = 0;

    /* Get field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Stage field control structure. */
    rv = _field_stage_control_get(unit, f_st->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Check that stat was requested during statistics entity creation. */
    for (idx1 = 0; idx1 < f_st->nstat; idx1++) {
        if (stat == f_st->stat_arr[idx1]) {
            break;
        }
    }
    if (idx1 == f_st->nstat) {
        return (BCM_E_PARAM);
    }

    /* Get hw indexes and flags needed to compose requested statistic.*/
    rv = fc->functions.fp_stat_index_get(unit, f_st, stat, &idx1, 
                                         &idx2, &flags);
    BCM_IF_ERROR_RETURN(rv);

    /* Get accumulated counter value at primary index. */
    if (_FP_INVALID_INDEX != idx1) {
        rv = _field_sw_counter_get(unit, stage_fc, idx1, &packet_count_1,
                                   &byte_count_1);
        BCM_IF_ERROR_RETURN(rv);
    }

    /* Get accumulated counter value at secondary index. */
    if (_FP_INVALID_INDEX != idx2) {
        rv = _field_sw_counter_get(unit, stage_fc, idx2, &packet_count_2,
                                   &byte_count_2);
        BCM_IF_ERROR_RETURN(rv);
    }

    /* Get final counter value. */ 
    COMPILER_64_ZERO(*value);
    if (flags & _FP_STAT_BYTES) {
        if (flags & _FP_STAT_ADD) {
            COMPILER_64_ADD_64(byte_count_1, byte_count_2);
        } else if (flags & _FP_STAT_SUBSTRACT) {
            COMPILER_64_SUB_64(byte_count_1, byte_count_2);
        }
        COMPILER_64_OR(*value, byte_count_1);
    } else {
        if (flags & _FP_STAT_ADD) {
            COMPILER_64_ADD_64(packet_count_1, packet_count_2);
        } else if (flags & _FP_STAT_SUBSTRACT) {
            COMPILER_64_SUB_64(packet_count_1, packet_count_2);
        }
        COMPILER_64_OR(*value, packet_count_1);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stat_hw_free
 *
 * Purpose:
 *     Deallocate hw counter from an entry.
 * 
 * Parameters:
 *     unit      - (IN) BCM device number.  
 *     f_ent     - (IN) Entry statistics belongs to.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_stat_hw_free (int unit, _field_entry_t *f_ent)
{
    _field_entry_stat_t  *f_ent_st;  /* Field entry statistics structure. */
    _field_stat_t        *f_st;      /* Statistics entity descriptor.     */
    uint64               value;      /* 64 bit zero to reset hw value.    */
    int                  idx;        /* Statistics iteration index.       */
    int                  rv;         /* Operation return status.          */

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }
    f_ent_st = &f_ent->statistic;

    /* Skip uninstalled statistics entity. */
    if (0 == (f_ent_st->flags & _FP_ENTRY_STAT_INSTALLED)) {
        return (BCM_E_NONE);
    }

    /* No de-allocation is required for external FP. */
    if (_BCM_FIELD_STAGE_EXTERNAL == f_ent->fs->stage_id) {
        f_ent_st->flags &=  ~_FP_ENTRY_STAT_INSTALLED;
        return (BCM_E_NONE);
    }

    /* Read stat entity configuration. */
    BCM_IF_ERROR_RETURN(_bcm_field_stat_get(unit, f_ent_st->sid, &f_st));

    /* Decrement hw reference count. */
    if (f_st->hw_ref_count > 0) {
        f_st->hw_ref_count--;
    }

    /* Statistics is not used by any other entry. */
    if (f_st->hw_ref_count == 0) {
        COMPILER_64_ZERO(value);
        /* Read & Reset  individual statistics. */
        for (idx = 0; idx < f_st->nstat; idx++) {
            rv = _field_stat_value_get(unit, f_st, f_st->stat_arr[idx],
                                       f_st->stat_values + idx);
            if (BCM_FAILURE(rv)) {
                /* During system restart flex stat module 
                 * might be reinitialized before fp reinit. Hence
                 * calls to the flex stat module will result in BCM_E_NOT_FOUND 
                 * error code.
                 */
                if (0 == ((_BCM_FIELD_STAGE_LOOKUP == f_st->stage_id) &&
                          (BCM_E_NOT_FOUND == rv))) {
                    return rv;
                }
            } else {
                rv = _field_stat_value_set(unit, f_st, f_st->stat_arr[idx], value);
                BCM_IF_ERROR_RETURN(rv);
            }
        }
        /* Mark hw resource as unused in sw. */
        BCM_IF_ERROR_RETURN (_field_slice_counter_free(unit, f_ent, f_st));
    }

    /* 
     * If qualifiers have not been modified for this entry,
     * set Action only dirty flag.
     */
    if (0 == (f_ent->flags & _FP_ENTRY_DIRTY)) {
        f_ent->flags |= _FP_ENTRY_ACTION_ONLY_DIRTY;
    }

    f_ent_st->flags &= ~_FP_ENTRY_STAT_INSTALLED;

    /* Mark entry for reinstall. */
    f_ent->flags |= _FP_ENTRY_DIRTY;
    return (BCM_E_NONE);
}

/*
 * Function: 
 *    _field_entry_stat_detach
 *
 * Description:
 *       Detach statistics entity from Field processor entry.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      f_ent     - (IN) Field entry structure. 
 *      stat_id   - (IN) Statistics entity id.
 * Returns:
 *      BCM_E_XXX
 */
STATIC int 
_field_entry_stat_detach(int unit, _field_entry_t *f_ent, int stat_id)
{
    _field_stat_t       *f_st;     /* Internal statistics entity.  */
    _field_entry_stat_t *f_ent_st; /* Field entry stat structure.  */
    int                 rv;        /* Operation return status.     */

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    /* Make sure statistics entity attached to the entry. */
    f_ent_st = &f_ent->statistic;

    if (0 == (f_ent_st->flags & _FP_ENTRY_STAT_VALID)) {
        return (BCM_E_EMPTY);
    }

    /* Compare statistics entity id with attached entity id. */
    if (stat_id  != f_ent_st->sid) {
        return (BCM_E_PARAM);
    }

    /* Get statics entity descriptor structure. */
    rv = _bcm_field_stat_get(unit, f_ent_st->sid, &f_st);
    BCM_IF_ERROR_RETURN(rv);

    if (soc_feature(unit,soc_feature_advanced_flex_counter) && 
        (f_st->flex_mode != 0)) {
        if (_field_control[unit]->init == TRUE) {
            BCM_IF_ERROR_RETURN(bcm_esw_field_stat_detach(unit,f_ent_st->sid));
        } else {
            /* Special case where stat module might/might-not be initialized */
            /*  So ignoring return value */
            rv = bcm_esw_field_stat_detach(unit,f_ent_st->sid);
            if (BCM_FAILURE(rv)) {
                 FP_WARN(("FP(unit %d) WARN: ignoring return value %s\n",
                          unit,bcm_errmsg(rv)));
            }
        }
    }

    /* If entry was installed decrement hw reference counter. */
    rv = _field_stat_hw_free (unit, f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Decrement statistics entity reference counter. */
    f_st->sw_ref_count--;

    /* If no one else is using the entity and it is internal destroy it. */
    if ((1 == f_st->sw_ref_count) && (f_st->hw_flags & _FP_STAT_INTERNAL)) {
        rv = _field_stat_destroy(unit, f_ent_st->sid);
        BCM_IF_ERROR_RETURN(rv);
    }

    /* Detach policer from an entry. */
    f_ent_st->sid   = _FP_INVALID_INDEX;
    f_ent_st->flags = 0;

    /* Mark entry for reinstall. */
    f_ent->flags |= _FP_ENTRY_DIRTY;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stat_color_dependent
 *
 * Purpose:
 *    Check if statistics entity is color dependent.
 *
 * Parameters:
 *     unit            - (IN) BCM device number.
 *     f_st            - (IN) Field statistics entity..
 *     color_dependent - (IN) Field statistics entity..
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_stat_color_dependent(int unit, _field_stat_t *f_st, 
                            uint8 *color_dependent)
{
   /* Input parameters check. */
    if ((NULL == f_st) || (NULL == color_dependent)) {
        return (BCM_E_PARAM);
    }
#if defined(BCM_TRIDENT_SUPPORT)
    if ((SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) &&
        (f_st->stage_id == _BCM_FIELD_STAGE_INGRESS)) {
        switch (f_st->hw_mode & 0x7) {
            case (0x0):
            /* Fall thru */
            case (0x7):
                *color_dependent = FALSE;
                break;
            default:
                *color_dependent = TRUE;
                break;
        }
        switch ((f_st->hw_mode >> 3) & 0x7) {
            case (0x0):
            /* Fall thru */
            case (0x7):
                break;
            default:
                *color_dependent = TRUE;
                break;
        }
    } else 
#endif /* BCM_TRIDENT_SUPPORT */
    {
        switch (f_st->hw_mode) {
          case (0x0):
          case (0x1):
          case (0x2):
          case (0x9):
          case (0xa):
              *color_dependent = FALSE;
              break;
          default:
              *color_dependent = TRUE;
              break;
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stat_hw_mode_adjust
 *
 * Purpose:
 *     Ajust statistics entity mode based on
 *     allocated counter index.
 *       
 * Parameters:
 *     unit  - (IN)     Bcm device number.
 *     f_st  - (IN/OUT) Statistics entity.
 *     idx   - (IN)     Allocated hw index.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_stat_hw_mode_adjust(int unit, _field_stat_t *f_st, int idx)
{
    /* Input parameters check. */
    if (NULL == f_st) {
        return (BCM_E_PARAM);
    }

#if defined(BCM_TRIDENT_SUPPORT)
    if ((SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) &&
        (f_st->stage_id == _BCM_FIELD_STAGE_INGRESS)) {
        /* Adjust statistics hw mode  */
        if (0x1 == (idx & 0x1)) {
            if (f_st->hw_mode & 0x7) {
                f_st->hw_mode <<= 3;
            }
        } else {
            if (((f_st->hw_mode >> 3) & 0x7)) {
                f_st->hw_mode >>= 3;
            }
        }
    } else 
#endif /* BCM_TRIDENT_SUPPORT */
    {
        /* Adjust statistics hw mode  */
        if (0 == (idx & 0x1)) {
            if ((0xa == f_st->hw_mode) || (0x2 == f_st->hw_mode)) {
                f_st->hw_mode--;
            }
        } else {
            if ((0x9 == f_st->hw_mode) || (0x1 == f_st->hw_mode)) {
                f_st->hw_mode++;
            }
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_slice_counter_alloc
 *
 * Purpose:
 *     Allocate a counter from a slice.
 * 
 * Parameters:
 *     unit  - (IN)     Bcm device number.
 *     fs    - (IN)     Slice where counter resides.
 *     f_st  - (IN/OUT) Statistics entity.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_slice_counter_alloc(int unit, _field_slice_t *fs, _field_stat_t *f_st)
{
    int  idx;        /* Bitmap iteration index.     */
    int  idx_max;    /* Total number of counters.   */

    if ((NULL == fs) || (NULL == f_st)) {
        return (BCM_E_PARAM);
    } 

    idx_max = fs->counters_count;

    /* If counter is disabled  skip allocation. */
    if (0 == f_st->hw_mode) {
        return (BCM_E_NONE);
    }

    for (idx = 0; idx < idx_max; idx++) {
        /* Double entry counters. (e.g Red + Green) */
        if (0x2 == f_st->hw_entry_count) {
            if (0 != (idx % 2)) {
                /* Skip odd indexes. */
                continue; 
            }
            if ((0 == _FP_COUNTER_BMP_TEST(fs->counter_bmp, idx)) &&  
                (0 == _FP_COUNTER_BMP_TEST(fs->counter_bmp, (idx + 1)))) {
                /* Mark counter as used. */
                _FP_COUNTER_BMP_ADD(fs->counter_bmp, idx);
                _FP_COUNTER_BMP_ADD(fs->counter_bmp, idx + 1);
                /* Save counter information in statistics entity structure. */
                f_st->pool_index = fs->slice_number;
                f_st->hw_index = idx/2;
                /* Set counter dirty flag. */
                break;
            }
        }

        /* Single entry counters. (e.g Bytes) */
        if (0 == _FP_COUNTER_BMP_TEST(fs->counter_bmp, idx)) {
            /* Mark counter as used. */
            _FP_COUNTER_BMP_ADD(fs->counter_bmp, idx);
            /* Save counter information in statistics entity structure. */
            f_st->pool_index = fs->slice_number;
#if defined (BCM_FIREBOLT2_SUPPORT)
            if (SOC_IS_FIREBOLT2(unit) && (_BCM_FIELD_STAGE_EGRESS == f_st->stage_id)) {
                /* FB2 - doesn't have counter pairs in stage egress. */
                f_st->hw_index = idx;
            } else 
#endif /* BCM_FIREBOLT2_SUPPORT */
            {
                f_st->hw_index = (idx/2); 
                /* Adjust statistics hw mode */
                BCM_IF_ERROR_RETURN(_field_stat_hw_mode_adjust(unit, f_st, idx));
            }
            break;
        }
    }
    if (idx == idx_max) {
        return (BCM_E_RESOURCE);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_counter_hw_alloc
 *
 * Purpose:
 *     Allocate a counter/s for an entry from a slice.
 * 
 * Parameters:
 *     unit      - (IN) BCM device number.  
 *     stage_fc  - (IN) Stage field control structure. 
 *     f_ent     - (IN/OUT) Entry array policer belongs to.
 *     fs        - (IN) Desired slice for the counter.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_counter_hw_alloc(int unit, _field_entry_t *f_ent, _field_slice_t *fs) 
{
    uint8                  color_dependent;/* Statistics is color based.*/
    uint8                  entry_part; /* Field entry tcam part.        */
    _field_entry_stat_t    *f_ent_st;  /* Field entry stat structure.   */
    _field_entry_policer_t *f_ent_pl;  /* Field entry policer structure.*/
    _field_stage_t         *stage_fc;  /* Stage field control.          */
    _field_group_t         *fg;        /* Field group structure.        */
    _field_stat_t          *f_st;      /* Field statistics descriptor.  */
    int                    rv;         /* Operation return status.      */

    /* Input parameters check. */
    if ((NULL == f_ent) || (NULL == fs)) {
        return (BCM_E_PARAM);
    }

    fg       = f_ent->group;
    f_ent_pl = f_ent->policer;
    f_ent_st = &f_ent->statistic;

    /* Reject unused counters. */
    if (0 == (f_ent_st->flags & _FP_ENTRY_STAT_VALID)) {
        return (BCM_E_PARAM);
    }

    /* Read policer configuration. */
    BCM_IF_ERROR_RETURN(_bcm_field_stat_get(unit, f_ent_st->sid, &f_st));

#if defined(BCM_TRIUMPH2_SUPPORT)
    /* Allocation is external for vfp counters. */
    if (_BCM_FIELD_STAGE_LOOKUP == fg->stage_id) {
       if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
        return _bcm_esw_flex_stat_enable_set(unit, _bcmFlexStatTypeFp,
                                             _bcm_esw_fp_flex_stat_index_set,
                                              (void *)f_st, f_st->sid, TRUE);
       }
    }
#endif /* BCM_TRIUMPH2_SUPPORT */

    /* Get entry stage control structure. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc); 
    BCM_IF_ERROR_RETURN (rv);


    /* Verify if statistics entity is color dependent. */
    rv = _field_stat_color_dependent(unit, f_st, &color_dependent);
    BCM_IF_ERROR_RETURN (rv);

    if ((0 == (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS)) &&
        (f_ent_pl->flags & _FP_POLICER_INSTALLED) &&
        (color_dependent)) {
        /* If meter is present, counter must reside in the same slice. */ 
        if (f_ent->flags & _FP_ENTRY_POLICER_IN_SECONDARY_SLICE) {
            rv = _field_slice_counter_alloc(unit, fs + 1, f_st);
            if (BCM_SUCCESS(rv)) {
                /* Get primary entry from the second slice. */
                rv = _bcm_field_entry_flags_to_tcam_part (_FP_ENTRY_SECONDARY, 
                                                          fg->flags, &entry_part);
                BCM_IF_ERROR_RETURN(rv);
                f_ent->flags |= _FP_ENTRY_STAT_IN_SECONDARY_SLICE;
                sal_memcpy(&f_ent[entry_part].statistic, &f_ent->statistic, 
                           sizeof(_field_entry_stat_t));
                f_ent[entry_part].statistic.flags |= _FP_ENTRY_STAT_INSTALLED;
            }
        } else { 
            rv = _field_slice_counter_alloc(unit, fs, f_st);
        }
    } else {
        rv = _field_slice_counter_alloc(unit, fs, f_st);
        if((BCM_FAILURE(rv)) &&
           ((f_ent->group->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) ||
            (f_ent->group->flags & _FP_GROUP_SPAN_TRIPLE_SLICE))) {
            rv = _field_slice_counter_alloc(unit, fs + 1, f_st);
            if (BCM_SUCCESS(rv)) {
                rv = _bcm_field_entry_flags_to_tcam_part (_FP_ENTRY_SECONDARY, 
                                                          fg->flags, &entry_part);
                BCM_IF_ERROR_RETURN(rv);
                f_ent->flags |= _FP_ENTRY_STAT_IN_SECONDARY_SLICE;
                sal_memcpy(&f_ent[entry_part].statistic, &f_ent->statistic, 
                           sizeof(_field_entry_stat_t));
                f_ent[entry_part].statistic.flags |=  _FP_ENTRY_STAT_INSTALLED;
            }
        }
    }
    return (rv);
}

/*
 * Function:
 *     _field_stat_hw_alloc 
 *
 * Purpose:
 *     Allocate counters required for entry installation.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry array.
 *     fs        - (IN) Slice to allocate a counter. 
 * Returns:
 *     BCM_E_XXX
 * Notes:
 */
STATIC int
_field_stat_hw_alloc(int unit, _field_entry_t *f_ent)
{
    _field_entry_stat_t    *f_ent_st;  /* Field entry stat structure.   */
    _field_stat_t          *f_st;      /* Field statistics descriptor.  */
    int                    rv;         /* Operation return status.      */
    int                    idx;        /* Statistics values iterator.   */
    _field_stage_t         *stage_fc; /* Field stage control structure.*/

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    f_ent_st = &f_ent->statistic;

    /* Skip entries without countres attached. */
    if ((0 == (f_ent_st->flags & _FP_ENTRY_STAT_VALID)) ||
        (f_ent_st->flags & _FP_ENTRY_STAT_EMPTY)) {
        return (BCM_E_NONE);
    }

    /* No allocation is required for external FP. */
    if (_BCM_FIELD_STAGE_EXTERNAL == f_ent->fs->stage_id) {
        f_ent_st->flags |=  _FP_ENTRY_STAT_INSTALLED;
        return (BCM_E_NONE);
    }

    /* Read statistics entity configuration. */
    rv = _bcm_field_stat_get(unit, f_ent_st->sid, &f_st);
    BCM_IF_ERROR_RETURN (rv);
#if defined(BCM_KATANA_SUPPORT)
    BCM_IF_ERROR_RETURN(_field_stage_control_get(unit,
            f_ent->fs->stage_id, &stage_fc));
    if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
        if (f_st->flex_mode != 0) {
          return BCM_E_NONE;
        }
        if (SOC_IS_KATANA(unit) 
            && (stage_fc->stage_id == _BCM_FIELD_STAGE_LOOKUP)) {
            return BCM_E_NONE;
        }
    }
#endif

    /* Allocate statistics entity hw index. */
    if (_FP_INVALID_INDEX == f_st->hw_index) {
        rv = _field_counter_hw_alloc(unit, f_ent, f_ent->fs);
        BCM_IF_ERROR_RETURN(rv);
    }

    /* Check if entry and stat are referencing same physical slice */
    if (_BCM_FIELD_STAGE_INGRESS == f_ent->fs->stage_id) {
        /* Get stage control information. */
        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit,
            f_ent->fs->stage_id, &stage_fc));

        if ((0 == (stage_fc->flags & _FP_STAGE_GLOBAL_COUNTERS))
            && _FP_INVALID_INDEX != f_st->hw_index) {
            if (f_ent->fs->slice_number != f_st->pool_index) {
                FP_ERR(("FP(unit %d) Error: Entry:%d belongs to an expanded group.\n",
                    unit, f_ent->eid));
                FP_ERR(("Create a new Stat and attach to Entry. "));
                FP_ERR(("Counters are per-slice resource.\n"));
                return (BCM_E_CONFIG);
            }
        }
    }

    /* Increment statistics hw reference count. */
    if (0 == (f_ent_st->flags & _FP_ENTRY_STAT_INSTALLED)) {
        f_ent_st->flags |=  _FP_ENTRY_STAT_INSTALLED;
        f_st->hw_ref_count++;

        if (1 == f_st->hw_ref_count) {
            /* Write individual statistics privious value. */
            for (idx = 0; idx < f_st->nstat; idx++) {
                rv = _field_stat_value_set(unit, f_st, f_st->stat_arr[idx], 
                                           f_st->stat_values[idx]);
                BCM_IF_ERROR_RETURN(rv);
            }
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_mirror_dest_delete
 * Purpose:
 *     Unset mirroring destination & disable mirroring for rule matching 
 *     packets.
 * Parameters:
 *     unit     - (IN) BCM device number
 *     fa       - (IN) Field action descriptor. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_mirror_dest_delete(int unit, _field_entry_t  *f_ent, _field_action_t *fa)
{
    uint32 mirror_flags;      /* Mirror module flags.     */ 

    /* Input parameters check */
    if ((NULL == fa) || (NULL == f_ent)) {
        return (BCM_E_PARAM);
    }

    /* Set mirror flags. */
    if (bcmFieldActionMirrorIngress == fa->action) {
        mirror_flags = BCM_MIRROR_PORT_INGRESS;
    }  else if (bcmFieldActionMirrorEgress == fa->action) {
        if (_BCM_FIELD_STAGE_EGRESS == f_ent->group->stage_id) {
            mirror_flags = BCM_MIRROR_PORT_EGRESS_TRUE;
        } else {
            /* Stage Ingress */
            mirror_flags = BCM_MIRROR_PORT_EGRESS;
        }
    } else {
        return (BCM_E_PARAM);
    }

    /* Make sure mtp index is valid. */
    if (_FP_INVALID_INDEX == fa->hw_index) {
        return (BCM_E_NONE);
    }

    BCM_IF_ERROR_RETURN
        (_bcm_esw_mirror_fp_dest_delete(unit, fa->hw_index, mirror_flags));

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_mirror_dest_add
 * Purpose:
 *     Set mirroring destination & enable mirroring for rule matching 
 *     packets.
 * Parameters:
 *     unit     - (IN) BCM device number
 *     fa       - (IN) field action 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_mirror_dest_add (int unit, _field_entry_t *f_ent, _field_action_t *fa)
{
    uint32 mirror_flags;      /* Mirror module flags.     */ 
    
    /* Input parameters check. */
    if ((NULL == fa) || (NULL == f_ent)) {
        return (BCM_E_PARAM);
    }

    /* Set mirror flags. */
    if (bcmFieldActionMirrorIngress == fa->action) {
        mirror_flags = BCM_MIRROR_PORT_INGRESS;
    }  else if (bcmFieldActionMirrorEgress == fa->action) {
        if (_BCM_FIELD_STAGE_EGRESS == f_ent->group->stage_id) {
            mirror_flags = BCM_MIRROR_PORT_EGRESS_TRUE;
        } else {
            /* Stage Ingress */
            mirror_flags = BCM_MIRROR_PORT_EGRESS;
        }
    } else {
        return (BCM_E_PARAM);
    }

    return _bcm_esw_mirror_fp_dest_add(unit,  fa->param[0], fa->param[1], 
                                       mirror_flags, &fa->hw_index);
}


/*
 * Function: 
 *      _field_slice_counter_available
 * Purpose: 
 *      Checks if counter might be installed in a slice. 
 * Parameters:
 *   unit       - (IN) BCM device number. 
 *   f_st       - (IN) Field statistics entity. 
 *   fs         - (IN) Destination slice. 
 * Returs:
 *   BCM_E_XXX  
 */
STATIC int
_field_slice_counter_available(int unit, _field_stat_t *f_st, _field_slice_t *fs)
{
    int  idx;            /* Counters iteration index.        */ 

    /* Input parameters check. */
    if ((NULL == f_st) || (NULL == fs)) {
        return (BCM_E_PARAM);
    }

    /* Check if target slice has a free counters */
    for (idx = 0; idx < fs->counters_count; idx++) {
        if (0x2 == f_st->hw_entry_count) {
            if (0 != (idx % 2)) {
                /* Skip odd indexes. */
                continue;
            }
            if ((0 == _FP_COUNTER_BMP_TEST(fs->counter_bmp, idx)) &&
                (0 == _FP_COUNTER_BMP_TEST(fs->counter_bmp, (idx+ 1)))) {
                    break;
            }
        } else if (0 == _FP_COUNTER_BMP_TEST(fs->counter_bmp, idx)) {
            break;
        }
    }

    if (idx == fs->counters_count) {
        return (BCM_E_RESOURCE);
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *     _field_slice_meter_available
 * Purpose:  
 *      Checks if policer might be installed in a slice. 
 * Parameters:
 *   unit       - (IN) BCM device number. 
 *   f_pl       - (IN) Policer descriptor.
 *   fs         - (IN) Destination slice. 
 * Returs:
 *   BCM_E_XXX  
 */
STATIC int
_field_slice_meter_available(int unit, _field_policer_t *f_pl, _field_slice_t *fs)
{
    int   idx;            /* Meters iteration index.       */

    /* Input parameters check. */
    if ((NULL == f_pl) || (NULL == fs)) {
        return (BCM_E_PARAM);
    }

    /* Check if target slice has a free meter */
    for (idx = 0; idx < fs->meters_count; idx++) {
#if defined (BCM_FIREBOLT_SUPPORT)
        if (SOC_IS_FB_FX_HX(unit)) {
            if ((bcmPolicerModePeak != f_pl->cfg.mode) &&
                (bcmPolicerModeCommitted != f_pl->cfg.mode)) {
                if (0 != (idx % 2)) {
                    /* skip odd */
                    continue;
                }

                if ((0 == _FP_METER_BMP_TEST(fs->meter_bmp, idx)) &&
                    (0 == _FP_METER_BMP_TEST(fs->meter_bmp, idx + 1))) {
                    break;
                }
            }

            if (0 == _FP_METER_BMP_TEST(fs->meter_bmp, idx)) {
                break;
            }
 
        } else 
#endif
        {
            if (0 == _FP_METER_BMP_TEST(fs->meter_bmp, idx)) {
                break;
            }
        }
    }
    if (idx == fs->meters_count) {
        return (BCM_E_RESOURCE);
    }
    return (BCM_E_NONE);
}


/*
 * Function: _field_entry_install_slice_fit
 *
 * Purpose: Checks if slice has HW resource required for entry installation.
 * Parameters:
 *   unit        - (IN) BCM device number.
 *   stage_fc    - (IN) Stage field control.
 *   f_ent       - (IN) Entry to be inserted.
 *   fs          - (IN) Destination slice.
 * Returs:
 *   BCM_E_NONE - Entry fits the slice. 
 *   BCM_E_XXX  - Otherwise.
 */
STATIC int
_field_entry_install_slice_fit(int unit, _field_stage_t *stage_fc, 
                       _field_entry_t *f_ent, _field_slice_t *fs)
{
    _field_entry_policer_t *f_ent_pl;      /* Field entry policers.    */
    _field_entry_stat_t    *f_ent_st;      /* Field entry statistics.  */
    _field_stat_t          *f_st;          /* Field statistics entity. */
    _field_policer_t       *f_pl;          /* Field policer.           */
    _field_group_t         *fg;            /* Field group structure.   */
    uint8                  color_dependent;/* Stat is color dependend. */
    int                    rv;             /* Operation return status. */

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == f_ent) || (NULL == fs)) {
        return (BCM_E_PARAM);
    }
    fg = f_ent->group;

    /* Reset allocation flags. */
    f_ent->flags &= ~_FP_ENTRY_ALLOC_FROM_SECONDARY_SLICE;

    /* If device supports global meter pools or no meter installed -> no issue. */
    f_ent_pl = f_ent->policer;
    if ((stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS) ||
        (0 == (f_ent_pl->flags & _FP_POLICER_VALID))) {
        f_pl = NULL;
    }  else {
        rv = _bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl);
        BCM_IF_ERROR_RETURN(rv);
        if (_FP_INVALID_INDEX != f_pl->hw_index) {
            f_pl = NULL; /* NO allocation required. */
        }
    }

    /* If device supports global counters or no counter installed -> no issue. */
    f_ent_st = &f_ent->statistic;  
    if (_BCM_FIELD_STAGE_EXTERNAL == stage_fc->stage_id) {
        /* External counters are directly attached to an entry. */
        f_st = NULL;
    } else if ((stage_fc->flags & _FP_STAGE_GLOBAL_COUNTERS) ||
        (0 == (f_ent_st->flags & _FP_ENTRY_STAT_VALID))) {
        f_st = NULL;
    }  else {
        rv = _bcm_field_stat_get(unit, f_ent_st->sid, &f_st);
        BCM_IF_ERROR_RETURN(rv);
#if defined(BCM_KATANA_SUPPORT)
        if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
            if (f_st->flex_mode != 0) {
                return BCM_E_NONE; /* NO allocation required. */
            }
            if (stage_fc->stage_id == _BCM_FIELD_STAGE_LOOKUP) {
                return BCM_E_NONE;
            }
        }
#endif
        if (_FP_INVALID_INDEX != f_st->hw_index) {
            f_st = NULL; /* NO allocation required. */
        }
    }

    /* Check if counter & meter are available in primary slice. */
    rv = BCM_E_NONE;
    /*    coverity[new_values : FALSE]    */
    if (f_pl != NULL) {
        rv =  _field_slice_meter_available(unit, f_pl, fs);
    } 
    if ((f_st != NULL) && (BCM_SUCCESS (rv))) {
        rv = _field_slice_counter_available(unit, f_st, fs);
    }
    if (BCM_SUCCESS (rv)) {
        return (BCM_E_NONE);
    }

    if ((fg->flags  & _FP_GROUP_SPAN_DOUBLE_SLICE) ||
        (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE)) {
        /* No counters -> policer can be allocated from any slice. */
        /* No policers -> counter can be allocated from any slice. */
        if ((f_st == NULL) || (f_pl == NULL)) {
            return (BCM_E_NONE);
        }

        /*
         * Only if counter is color blind it might be allocated
         * in a slice a different s policer.
         */

        /* Check if statistics entity is color dependent. */
        rv = _field_stat_color_dependent(unit, f_st, &color_dependent);
        BCM_IF_ERROR_RETURN(rv); 
        if (FALSE == color_dependent) {
            return (BCM_E_NONE);
        }

        /* Check if counter & meter are available in secondary slice. */
        rv =  _field_slice_meter_available(unit, f_pl, fs + 1);
        if (BCM_SUCCESS (rv)) {
            rv =  _field_slice_counter_available(unit, f_st, fs + 1);
        }

        /* Policer must be allocated from secondary slice */ 
        if (BCM_SUCCESS (rv)) {
            f_ent->flags |= _FP_ENTRY_ALLOC_FROM_SECONDARY_SLICE;
            return (BCM_E_NONE);
        }
    }
    return (BCM_E_RESOURCE);
}

/*
 * Function: _field_entry_move_slice_fit
 *
 * Purpose: Checks if slice has HW resource required for entry movement.
 * Parameters:
 *   unit        - (IN) BCM device number.
 *   stage_fc    - (IN) Stage field control.
 *   f_ent       - (IN) Entry to be inserted.
 *   fs          - (IN) Destination slice.
 *   freed_counters - (INOUT) Number of counters to be freed by a planned move
 * Returs:
 *   BCM_E_NONE - Entry fits the slice. 
 *   BCM_E_XXX  - Otherwise.
 */
STATIC int
_field_entry_move_slice_fit(int unit, _field_stage_t *stage_fc, 
    _field_entry_t *f_ent, _field_slice_t *fs, int *freed_meters,
    int *freed_counters)
{
    _field_entry_policer_t *f_ent_pl;      /* Field entry policers.    */
    _field_entry_stat_t    *f_ent_st;      /* Field entry statistics.  */
    _field_stat_t          *f_st;          /* Field statistics entity. */
    _field_policer_t       *f_pl;          /* Field policer.           */
    _field_group_t         *fg;            /* Field group structure.   */
    uint8                  color_dependent;/* Stat is color dependend. */
    int                    rv = BCM_E_NONE;/* Operation return status. */

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == f_ent) || (NULL == fs)) {
        return (BCM_E_PARAM);
    }

    fg = f_ent->group;

    /* Reset allocation flags. */
    f_ent->flags &= ~_FP_ENTRY_ALLOC_FROM_SECONDARY_SLICE;

    /* If device supports global meter pools or no meter installed -> no issue. */
    f_ent_pl = f_ent->policer;
    if ((stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS) ||
        (0 == (f_ent_pl->flags & _FP_POLICER_VALID))) {
        f_pl = NULL;
    }  else {
        rv = _bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl);
        BCM_IF_ERROR_RETURN(rv);

        /* Reject policers shared by multiple entries. */
        if (2 != f_pl->sw_ref_count) {
            return (BCM_E_RESOURCE);
        }
    }

    /* If device supports global counters or no counter installed -> no issue. */
    f_ent_st = &f_ent->statistic;  
    if ((stage_fc->flags & _FP_STAGE_GLOBAL_COUNTERS) ||
        (0 == (f_ent_st->flags & _FP_ENTRY_STAT_VALID))) {
        f_st = NULL;
    }  else {
        rv = _bcm_field_stat_get(unit, f_ent_st->sid, &f_st);
        BCM_IF_ERROR_RETURN(rv);

        /* Reject counters shared by multiple entries. */
        if (2 != f_st->sw_ref_count) {
            return (BCM_E_RESOURCE);
        }
    }

    /* Check if counter & meter are available in primary slice. */

    rv = BCM_E_NONE;

    /* coverity[new_values : FALSE]    */
    if (f_pl != NULL && *freed_meters == 0)
    {
        rv =  _field_slice_meter_available(unit, f_pl, fs);
    } 

    if ((f_st != NULL) && (BCM_SUCCESS (rv)))
    {
        if (f_st->hw_entry_count > *freed_counters)
        {
            rv = _field_slice_counter_available(unit, f_st, fs);
        }
    }

    if (BCM_SUCCESS (rv))
    {
        *freed_meters = (f_pl != NULL) ? 1 : 0;
        *freed_counters = (f_st != NULL) ? f_st->hw_entry_count : 0;

        return (BCM_E_NONE);
    }

    if ((fg->flags  & _FP_GROUP_SPAN_DOUBLE_SLICE) ||
        (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE)) {
        /* No counters -> policer can be allocated from any slice. */
        /* No policers -> counter can be allocated from any slice. */
        if ((NULL == f_st) || (NULL == f_pl)) {
            return (BCM_E_NONE);
        }

        /*
         * Only if counter is color blind it might be allocated
         * in a slice a different s policer.
         */

        /* Check if statistics entity is color dependent. */
        rv = _field_stat_color_dependent(unit, f_st, &color_dependent);
        BCM_IF_ERROR_RETURN(rv); 
        if (FALSE == color_dependent) {
            return (BCM_E_NONE);
        }

        /* Check if counter & meter are available in secondary slice. */
        rv =  _field_slice_meter_available(unit, f_pl, fs + 1);
        if (BCM_SUCCESS (rv)) {
            rv =  _field_slice_counter_available(unit, f_st, fs + 1);
        }

        /* Policer must be allocated from secondary slice */ 
        if (BCM_SUCCESS (rv)) {
            f_ent->flags |= _FP_ENTRY_ALLOC_FROM_SECONDARY_SLICE;
            return (BCM_E_NONE);
        }
    }
    return (BCM_E_RESOURCE);
}

/*
 * Function:
 *      _field_action_hw_resources_free
 * Purpose:
 *      Free hw resources allocated for field action installation.
 * Parameters:
 *      unit     - (IN) BCM device number
 *      f_ent    - (IN) Field entry structure.
 *      fa       - (IN) Field action structure. 
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_field_action_hw_resources_free(int unit, _field_entry_t  *f_ent,
                                _field_action_t *fa)
{
    int rv;

    /* Input parameters check. */
    if ((NULL == f_ent) || (NULL == fa)) {
        return (BCM_E_PARAM);
    }

    switch (fa->action) {
      case bcmFieldActionMirrorIngress:
      case bcmFieldActionMirrorEgress:
          rv = _field_mirror_dest_delete(unit, f_ent, fa);
          BCM_IF_ERROR_RETURN(rv);
          break;
      case bcmFieldActionRedirectMcast:
#if defined(INCLUDE_L3)
      case bcmFieldActionRedirectIpmc:
#endif /* INCLUDE_L3 */
          if (soc_feature(unit, soc_feature_field_action_redirect_ipmc)){
              break;
          }
      case bcmFieldActionRedirectPbmp:
      case bcmFieldActionEgressMask:
      case bcmFieldActionEgressPortsAdd:
          /* Applicable to stage ingress on TRX devices only. */
          if ((0 == SOC_IS_TRX(unit)) ||
              (_BCM_FIELD_STAGE_INGRESS != f_ent->group->stage_id)) {
              break;
          }
#if defined(BCM_TRX_SUPPORT)
          rv = _bcm_field_trx_redirect_profile_delete(unit, fa->hw_index);
          BCM_IF_ERROR_RETURN(rv);
#endif /* BCM_TRX_SUPPORT */
          break;
#if defined(INCLUDE_L3)
#if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_TRX_SUPPORT)
      case bcmFieldActionSrcMacNew:
      case bcmFieldActionDstMacNew:
      case bcmFieldActionOuterVlanNew:
          if (soc_feature(unit, soc_feature_field_action_l2_change)) {
              rv = _bcm_field_l2_actions_hw_free(unit, f_ent,
                        _FP_ACTION_HW_FREE);
              BCM_IF_ERROR_RETURN(rv);
          }
          break;
#endif /* BCM_TRX_SUPPORT || BCM_FIREBOLT2_SUPPORT */
#endif /* INCLUDE_L3 */

      default:
          break;
    }
    fa->hw_index = _FP_INVALID_INDEX;
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_mtp_hw_free
 *
 * Purpose:
 *     Free mtp indexes used in field entry
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry descriptor.
 * Returns:
 *     BCM_E_XXX
 * Notes:
 */
STATIC int
_field_mtp_hw_free (int unit, _field_entry_t *f_ent)
{
    _field_action_t *fa;        /* Field action descriptor. */
    int rv;                     /* Operation return status. */

    /* Extract action info from the entry structure. */
    for (fa = f_ent->actions; fa != NULL; fa = fa->next) {
        /* Allocate mtp destination only for mirroring actions */
        if ((bcmFieldActionMirrorIngress != fa->action) &&
            (bcmFieldActionMirrorEgress != fa->action)) {
            continue;
        }

        if (_FP_INVALID_INDEX == fa->hw_index) {
            continue;
        }
        rv = _field_action_hw_resources_free(unit, f_ent, fa);
        BCM_IF_ERROR_RETURN(rv); 
    }

    return (BCM_E_NONE);
}


/*
 * Function:
 *      _field_invalid_actions_remove
 * Purpose:
 *      Remove deleted actions from entry actions
 *      linked list.
 * Parameters:
 *      unit  - (IN) BCM device number
 *      f_ent - (IN) Field entry structure.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_field_invalid_actions_remove(int unit, _field_entry_t  *f_ent)
{
    _field_action_t     *fa;
    _field_action_t     *fa_prev = NULL;
    _field_action_t     *fa_next = NULL;
    int                 rv;

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    /* Find the action in the entry */
    fa = f_ent->actions; /* start at head */
    while (fa != NULL) {
        fa_next = fa->next;
        if (fa->flags & _FP_ACTION_VALID) {
            fa_prev = fa;
            fa      = fa_next;
            continue;
        }

        if (_FP_INVALID_INDEX != fa->hw_index) {
            rv = _field_action_hw_resources_free(unit, f_ent, fa);
            BCM_IF_ERROR_RETURN(rv);
        }

        if (fa_prev != NULL) {
            fa_prev->next = fa->next;
        } else { /* matched head of list */
            f_ent->actions = fa_next;
        }

        /* okay to free action */
        sal_free(fa);
        fa = fa_next;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_mtp_hw_alloc
 *
 * Purpose:
 *     Allocate mtp indexes required for entry installation.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry descriptor.
 * Returns:
 *     BCM_E_XXX
 * Notes:
 */
STATIC int
_field_mtp_hw_alloc (int unit, _field_entry_t *f_ent)
{
    _field_action_t *fa;  /* Field action descriptor. */
    int rv;               /* Operation return status. */

    /* Extract action info from the entry structure. */
    for (fa = f_ent->actions; fa != NULL; fa = fa->next) {
        /* Allocate mtp destination only for mirroring actions */
        if ((bcmFieldActionMirrorIngress != fa->action) &&
            (bcmFieldActionMirrorEgress != fa->action)) {
            continue;
        }

        if (_FP_INVALID_INDEX != fa->hw_index) {
            rv =  _field_action_hw_resources_free(unit, f_ent, fa);
            BCM_IF_ERROR_RETURN(rv);
        }

        /* Allocate mirror destination. */
        rv = _field_mirror_dest_add(unit, f_ent, fa);
        if (BCM_FAILURE(rv)) {
            _field_mtp_hw_free(unit, f_ent);
            return (rv);
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_redirect_profile_hw_free
 *
 * Purpose:
 *     Free redirect profile indexes required for entry installation.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry descriptor.
 *     flags     - (IN) Free flags (old/new/both). 
 * Returns:
 *     BCM_E_XXX
 * Notes:
 */
STATIC int
_field_redirect_profile_hw_free(int unit, _field_entry_t *f_ent, uint32 flags)
{
    _field_action_t *fa;  /* Field action descriptor. */
    int rv = BCM_E_NONE;  /* Operation return status. */

    /* Applicable to stage ingress on TRX devices only. */
    if ((0 == SOC_IS_TRX(unit)) ||
        (_BCM_FIELD_STAGE_INGRESS != f_ent->group->stage_id &&
         _BCM_FIELD_STAGE_EXTERNAL != f_ent->group->stage_id)) {
        return (BCM_E_NONE);
    }

    /* Extract the policy info from the entry structure. */
    for (fa = f_ent->actions; fa != NULL; fa = fa->next) {
        switch (fa->action) {
          case bcmFieldActionRedirectMcast:
#if defined(INCLUDE_L3)
          case bcmFieldActionRedirectIpmc:
#endif /* INCLUDE_L3 */
              if (soc_feature(unit, soc_feature_field_action_redirect_ipmc)){
                  break;
              }
          case bcmFieldActionRedirectPbmp:
          case bcmFieldActionRedirectBcastPbmp:
          case bcmFieldActionEgressMask:
          case bcmFieldActionEgressPortsAdd:
#if defined(BCM_TRX_SUPPORT)
              if ((flags & _FP_ACTION_RESOURCE_FREE) && 
                  (_FP_INVALID_INDEX != fa->hw_index)) {
                  rv = _bcm_field_trx_redirect_profile_delete(unit, 
                                                              fa->hw_index);
                  BCM_IF_ERROR_RETURN(rv);
                  fa->hw_index = _FP_INVALID_INDEX;
              } 

              if ((flags & _FP_ACTION_OLD_RESOURCE_FREE) && 
                  (_FP_INVALID_INDEX != fa->old_index)) {
                  rv = _bcm_field_trx_redirect_profile_delete(unit,
                                                              fa->old_index);
                  BCM_IF_ERROR_RETURN(rv);
                  fa->old_index = _FP_INVALID_INDEX;
              }
              break;
#endif /* BCM_TRX_SUPPORT */
          default:
              break;
        }
    }
    return (rv);
}


/*
 * Function:
 *     _field_redirect_profile_hw_alloc
 *
 * Purpose:
 *     Allocate redirect profile index required for entry installation.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry descriptor.
 * Returns:
 *     BCM_E_XXX
 * Notes:
 */
STATIC int
_field_redirect_profile_hw_alloc (int unit, _field_entry_t *f_ent)
{
    int rv = BCM_E_NONE;  /* Operation return status.     */
#if defined (BCM_TRX_SUPPORT)
    _field_action_t *fa;  /* Field action descriptor.     */

    int ref_count;        /* Profile use reference count. */

    /* Applicable to stage ingress on TRX devices only. */
    if ((0 == SOC_IS_TRX(unit)) || 
        (_BCM_FIELD_STAGE_INGRESS != f_ent->group->stage_id &&
         _BCM_FIELD_STAGE_EXTERNAL != f_ent->group->stage_id)) {
        return (BCM_E_NONE);
    }

    /* Extract the policy info from the entry structure. */
    for (fa = f_ent->actions; fa != NULL; fa = fa->next) {
        switch (fa->action) {
          case bcmFieldActionRedirectMcast:
#if defined(INCLUDE_L3)
          case bcmFieldActionRedirectIpmc:
#endif /* INCLUDE_L3 */
              if (soc_feature(unit, soc_feature_field_action_redirect_ipmc)){
                  break;
              }
          case bcmFieldActionRedirectPbmp:
          case bcmFieldActionRedirectBcastPbmp:
          case bcmFieldActionEgressMask:
          case bcmFieldActionEgressPortsAdd:
              fa->old_index = fa->hw_index;

              rv = _bcm_field_trx_redirect_profile_alloc(unit, f_ent, fa);
              if ((BCM_E_RESOURCE == rv) && 
                  (_FP_INVALID_INDEX != fa->old_index)) {
                  /* Destroy old profile ONLY 
                   * if it is not used by other entries.
                   */
                  rv = _bcm_field_trx_redirect_profile_ref_count_get(unit,
                                                                     fa->old_index,
                                                                     &ref_count);
                  BCM_IF_ERROR_RETURN(rv);
                  if (ref_count > 1) {
                      return (BCM_E_RESOURCE);
                  }
                  rv = _bcm_field_trx_redirect_profile_delete(unit, fa->old_index);
                  BCM_IF_ERROR_RETURN(rv);

                  /* Destroy old profile is no longer required. */
                  fa->old_index = _FP_INVALID_INDEX;

                  /* Reallocate profile for new action. */
                  rv = _bcm_field_trx_redirect_profile_alloc(unit, f_ent, fa);
              } 
              break;
          default:
              break;
        }
        if (BCM_FAILURE(rv)) {
            _field_redirect_profile_hw_free(unit, f_ent, _FP_ACTION_HW_FREE);
            break;
        }
    }
#endif /* BCM_TRX_SUPPORT */
    return (rv);
}

/*
 * Function:
 *     _field_port_filter_enable_set
 *
 * Purpose:
 *     Set the filter enable state in the Port Tables.
 *
 * Parameters:
 *     unit   - (IN)BCM device number. 
 *     fc     - (IN)Field control structure. 
 *     state  - (IN) TRUE = to enable 
 *                   FALSE = disable filtering.
 * 
 * Returns:
 *     BCM_E_NONE  - Success
 *     BCM_E_XXX   - From table read/write
 */
int 
_field_port_filter_enable_set(int unit, _field_control_t *fc, uint32 state)
{
    int port;                      /* Port iterator.               */
    int ret_val = BCM_E_NONE;      /* Operation return value.      */
    bcm_port_config_t  port_config;/* Device port config structure.*/

    /* Input parameters check. */
    if (NULL == fc || ((state != TRUE) && (state != FALSE))) {
        return (BCM_E_PARAM);
    }

    state = (state) ? 1 : 0;

    /* Read device port configuration. */ 
    BCM_IF_ERROR_RETURN(bcm_esw_port_config_get(unit, &port_config));

    FP_LOCK(fc);

    /* Iterate over all the ports but CPU set Lookup filtering. */
    BCM_PBMP_ITER(port_config.port, port) {
        /* Set field  enable to the hw. */
        ret_val =  bcm_esw_port_control_set(unit, port, 
                                            bcmPortControlFilterLookup, state);

        if (BCM_E_UNAVAIL == ret_val) {
            /* Device doesn't support lookup filtering. */
            break;
        }

        if (BCM_FAILURE(ret_val)) {
            FP_UNLOCK(fc);
            return (ret_val);
        }
    }

    /* Iterate over all the ports but CPU set ingress filtering. */
    BCM_PBMP_ITER(port_config.port, port) {
        /* Set field  enable to the hw. */
        ret_val =  bcm_esw_port_control_set(unit, port, 
                                            bcmPortControlFilterIngress, state);
        if (BCM_FAILURE(ret_val)) {
            FP_UNLOCK(fc);
            return (ret_val);
        }
    }

    /* Iterate over all the ports set egress filtering. */
    BCM_PBMP_ITER(port_config.all, port) {
        /* Set field  enable to the hw. */
        ret_val =  bcm_esw_port_control_set(unit, port, 
                                            bcmPortControlFilterEgress, state);

        if (BCM_E_UNAVAIL == ret_val) {
            /* Device doesn't support egress filtering. */
            break;
        }

        if (BCM_FAILURE(ret_val)) {
            FP_UNLOCK(fc);
            return (ret_val);
        }
    }
    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: _field_qualifier_gport_resolve
 *
 * Purpose:
 *     Resolves gport as parameter of qualifier.
 *
 * Parameters:
 *     unit     - (IN) BCM device number
 *     gport    - (IN) GPORT to resolve 
 *     mask     - (IN) qualifier mask, in case of gport must be -1
 *     out_p    - (OUT) port encoded into gport.
 *     out_m    - (OUT) module encoded into gport.
 *     out_t    - (OUT) trunk encoded into gport. 
 *
 * Returns:
 *     BCM_E_NONE      - No errors.
 *     BCM_E_XXX       - Otherwise.
 */

STATIC int 
_field_qualifier_gport_resolve(int unit, bcm_gport_t gport, int mask, 
                               int *out_p, int *out_m, int *out_t)
{
    bcm_port_t      port;
    bcm_module_t    modid;
    bcm_trunk_t     tgid = BCM_TRUNK_INVALID;
    int             id; 

    /* In case of gport mask must be exact match */
    if (BCM_FIELD_EXACT_MATCH_MASK != mask) {
        return BCM_E_PARAM;
    }

    BCM_IF_ERROR_RETURN(
        _bcm_esw_gport_resolve(unit, gport, &modid, &port, &tgid, &id));

    if (-1 != id) {
        return BCM_E_PORT;
    }

    if (BCM_TRUNK_INVALID != tgid && NULL == out_t) {
        return BCM_E_PORT;
    }
    if (NULL != out_t) {
        *out_t = tgid;
    }
    if (NULL != out_m) {
        *out_m = modid;
    }
    if (NULL != out_p) {
        *out_p = port;
    }

    return (BCM_E_NONE);
}

/*
 * Function: _field_params_hw_to_api_adapt
 *
 * Purpose:
 *     Adapts action parameters from HW to API space.
 *
 * Parameters:
 *     unit   - (IN) BCM device number
 *     action - (IN)Action to adapt parameters for (bcmFieldActionXXX)
 *     param0 - (IN/OUT)Action parameter 
 *     param1 - (IN/OUT)Action parameter 
 *
 * Returns:
 *     BCM_E_NONE      - No errors.
 *     BCM_E_XXX       - Otherwise.
 */

STATIC int 
_field_params_hw_to_api_adapt(int unit, bcm_field_action_t action, 
                              uint32 *param0, uint32 *param1)
{
    int                 isGport;
    _bcm_gport_dest_t   dest;

    _bcm_gport_dest_t_init(&dest);
    BCM_IF_ERROR_RETURN(
        bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport));

    switch (action) {
        case bcmFieldActionRedirect: 
            if (isGport) {
                dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
                dest.modid = *param0;
                dest.port = *param1;
                BCM_IF_ERROR_RETURN(
                    _bcm_esw_gport_construct(unit, &dest, (bcm_gport_t*)param1));
                *param0 = -1;   /* If gport requested param0 should be ignored */
            }
            break;
        case bcmFieldActionRedirectTrunk:
            if (isGport) {
                dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
                dest.tgid = *param0;
                BCM_IF_ERROR_RETURN(
                    _bcm_esw_gport_construct(unit, &dest, (bcm_gport_t*)param0));
                *param1 = -1;   /* If gport requested param1 should be ignored */
            }
            break;
        default:
            break;
    }
    return (BCM_E_NONE);
}

/*
 * Function: _field_params_api_to_hw_adapt
 *
 * Purpose:
 *     Adapts action parameters from API to HW space.
 *
 * Parameters:
 *     unit   - (IN) BCM device number
 *     action - (IN)Action to adapt parameters for (bcmFieldActionXXX)
 *     param0 - (IN/OUT)Action parameter 
 *     param1 - (IN/OUT)Action parameter 
 *
 * Returns:
 *     BCM_E_NONE      - No errors.
 *     BCM_E_XXX       - Otherwise.
 */

STATIC int 
_field_params_api_to_hw_adapt(int unit, bcm_field_action_t action, 
                              uint32 *param0, uint32 *param1)
{
    bcm_module_t        l_modid;
    bcm_trunk_t         l_tgid;
    bcm_port_t          l_port;
    int                 id;


    switch (action) {
        case bcmFieldActionRedirect: 
            if (BCM_GPORT_IS_SET(*param1)) {
                BCM_IF_ERROR_RETURN(
                    _bcm_esw_gport_resolve(unit, *param1, &l_modid, &l_port, &l_tgid, &id)); 
                /* Do not modify param0 and param1 if id != -1 */
                if (-1 == id) {
                    if (BCM_TRUNK_INVALID != l_tgid) {
                        return BCM_E_PARAM;
                    }
                    *param1 = l_port;
                    *param0 = l_modid;
                }
            } 
            break;
        case bcmFieldActionRedirectTrunk:
            if (BCM_GPORT_IS_SET(*param0)) {
                BCM_IF_ERROR_RETURN(
                    _bcm_esw_gport_resolve(unit, *param0, &l_modid, &l_port, &l_tgid, &id)); 
                if ((-1 != id) || (BCM_TRUNK_INVALID == l_tgid) ){
                    return BCM_E_PARAM;
                }
                *param0 = l_tgid;
                *param1 = -1;   /* if param0 is trunk, param1 ignored */
            } 
            break;
        default:
            break;
    }

    return (BCM_E_NONE);
}

/*
 * Function: _field_meter_refresh_enable_set
 *
 * Purpose:
 *     Enable meters refresh cycle.
 *
 * Parameters:
 *     unit   - (IN) BCM device number
 *     fc     - (IN) Field control structure.
 *     state  - (IN) On/Off boolean.
 *
 * Returns:
 *     BCM_E_NONE      - No errors.
 *     BCM_E_XXX       - Otherwise.
 */
int 
_field_meter_refresh_enable_set(int unit, _field_control_t *fc, uint32 state)
{

    int rv = BCM_E_NONE;    /* Operation return status. */
#ifdef BCM_TRIUMPH_SUPPORT
    soc_reg_t  reg;
#endif /* BCM_TRIUMPH_SUPPORT */

    /* Input parameters check. */
    if (NULL == fc || ((state != TRUE) && (state != FALSE))) {
        return (BCM_E_PARAM);
    }

    state = (state) ? 1 : 0;

#ifdef BCM_TRIUMPH_SUPPORT
    if (SOC_IS_TR_VL(unit)) {
        reg = (SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit)) ? IESMIF_CONTROLr : IESMIF_CONTROL2r;
        if (SOC_REG_IS_VALID (unit, reg)) {
            if (SOC_REG_FIELD_VALID(unit, reg, FP_REFRESH_ENABLEf)) {
                rv = soc_reg_field32_modify(unit, reg, REG_PORT_ANY, 
                                        FP_REFRESH_ENABLEf, state);
                BCM_IF_ERROR_RETURN(rv);
            }
        }
        if(!SOC_IS_HURRICANE(unit)) {
            rv = soc_reg_field32_modify(unit, EFP_METER_CONTROLr, REG_PORT_ANY,
                                    EFP_REFRESH_ENABLEf, state);
            BCM_IF_ERROR_RETURN(rv);
        }

        if (SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) {
            rv = soc_reg_field32_modify(unit, AUX_ARB_CONTROL_2r, REG_PORT_ANY, 
                                    FP_REFRESH_ENABLEf, state);
            BCM_IF_ERROR_RETURN(rv);
        }
        return rv;
    }
#endif /* BCM_TRIUMPH_SUPPORT */

#ifdef BCM_SCORPION_SUPPORT
    if (SOC_IS_SC_CQ(unit)) {

        rv = soc_reg_field32_modify(unit, AUX_ARB_CONTROL_2r, REG_PORT_ANY,
                                    FP_REFRESH_ENABLEf, state);
        BCM_IF_ERROR_RETURN(rv);
        if (SOC_SWITCH_BYPASS_MODE_L3_ONLY != SOC_SWITCH_BYPASS_MODE(unit)) {
            rv =  soc_reg_field32_modify(unit, EFP_METER_CONTROLr, REG_PORT_ANY,
                                         EFP_REFRESH_ENABLEf, state);
        }
        return BCM_E_NONE;
    }
#endif /* BCM_SCORPION_SUPPORT */

#ifdef BCM_BRADLEY_SUPPORT
    if (SOC_IS_HBX(unit)) {
        uint32 sbs_ctrl;
        uint32 pipe_sel;
        BCM_IF_ERROR_RETURN(READ_SBS_CONTROLr(unit, &sbs_ctrl));
        pipe_sel = soc_reg_field_get(unit, SBS_CONTROLr, sbs_ctrl,
                                     PIPE_SELECTf);

        rv =soc_reg_field32_modify(unit, AUX_ARB_CONTROL_2r, REG_PORT_ANY,
                                   FP_REFRESH_ENABLEf, state);
        BCM_IF_ERROR_RETURN(rv);

        /* Flip between X and Y pipe */
        pipe_sel = (pipe_sel == 0) ? 1 : 0;
        soc_reg_field_set(unit, SBS_CONTROLr, &sbs_ctrl, PIPE_SELECTf,
                          pipe_sel);
        BCM_IF_ERROR_RETURN(WRITE_SBS_CONTROLr(unit, sbs_ctrl));

        rv = soc_reg_field32_modify(unit, AUX_ARB_CONTROL_2r, REG_PORT_ANY,
                                    FP_REFRESH_ENABLEf, state);
        BCM_IF_ERROR_RETURN(rv);                                                                        
        /* Restore original pipeline selection */
        pipe_sel = (pipe_sel == 0) ? 1 : 0;
        soc_reg_field_set(unit, SBS_CONTROLr, &sbs_ctrl, PIPE_SELECTf,
                          pipe_sel);
        return WRITE_SBS_CONTROLr(unit, sbs_ctrl);
    } 
#endif /* BCM_BRADLEY_SUPPORT */

#if defined(BCM_FIREBOLT2_SUPPORT)
    if (soc_feature(unit, soc_feature_field_multi_stage)) {
        rv = soc_reg_field32_modify(unit, EFP_METER_CONTROLr, REG_PORT_ANY,
                                    EFP_REFRESH_ENABLEf, state);
        BCM_IF_ERROR_RETURN(rv);
    } 
#endif /* BCM_FIREBOLT2_SUPPORT */

    rv = soc_reg_field32_modify(unit, AUX_ARB_CONTROLr, REG_PORT_ANY,
                                FP_REFRESH_ENABLEf, state);

    return (rv);
}


/*
 * Function:
 *     _field_stage_qualifiers_free
 * Purpose:
 *     De-initialize stage qaualifiers descriptors. 
 * Parameters:
 *     unit       - (IN) BCM device number.
 *     stage_fc   - (IN) Field Processor stage control structure. 
 *
 * Returns:
 *     BCM_E_NONE
 */
STATIC int
_field_stage_qualifiers_free(int unit, _field_stage_t *stage_fc)
{
    _bcm_field_qual_info_t  *f_qual; /* Qualifier descriptor.       */
    int idx;                         /* Qualifiers iteration index. */

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    if (NULL == stage_fc->f_qual_arr) {
        return (BCM_E_NONE);
    }

    for (idx = 0; idx < _bcmFieldQualifyCount; idx++) {
        f_qual = stage_fc->f_qual_arr[idx];

        /* Skip unused qualifiers. */
        if (NULL == f_qual) {
            continue;
        }
        /* Free qualifier configurations array. */
        if (NULL != f_qual->conf_arr) sal_free(f_qual->conf_arr);

        /* Free qualifier descriptor structure. */
        sal_free(f_qual);

        /* Mark qualifier as unused. */ 
        stage_fc->f_qual_arr[idx] = NULL;
    }

    /* Free qualifiers array. */
    sal_free(stage_fc->f_qual_arr);
    stage_fc->f_qual_arr = NULL;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_qual_list_destroy (INTERNAL)
 * Parameters:
 *     ff_qual_p - (IN) Freed list address. 
 *
 * Purpose:
 *     Frees the memory for a qualifier linked list.
 * Returns:
 *     None
 */
STATIC void
_field_qual_list_destroy (_qual_info_t **f_qual_p)
{
    _qual_info_t  *f_qual, *f_qual_old;

    f_qual = *f_qual_p;

    while (f_qual != NULL) {
        f_qual_old = f_qual;
        f_qual     = f_qual->next;
        sal_memset(f_qual_old, 0, sizeof(_qual_info_t));
        sal_free(f_qual_old);
    }
    *f_qual_p = NULL; /* Null out old list pointer. */
}


/*
 * Function:
 *     _field_stage_fpf_destroy
 *
 * Purpose:
 *     Free memory for qualifier and qset table. 
 *
 * Parameters:
 *     unit     - (IN)     BCM unit
 *     stage_fc - (IN/OUT) Stage to be destroy.
 * 
 * Returns:
 *     BCM_E_NONE  - Success
 *     BCM_E_XXX   - From table read/write
 */
STATIC int
_field_stage_fpf_destroy(int unit, _field_stage_t *stage_fc)
{
    int idx;  /* loop variable  */

    for (idx = 0; idx < FPF_SZ_MAX; idx++) {
        _field_qual_list_destroy(&(stage_fc->_field_table_fpf0[idx]));
        _field_qual_list_destroy(&(stage_fc->_field_table_fpf1[idx]));
        _field_qual_list_destroy(&(stage_fc->_field_table_fpf2[idx]));
        _field_qual_list_destroy(&(stage_fc->_field_table_fpf3[idx]));
        _field_qual_list_destroy(&(stage_fc->_field_table_fpf4[idx]));
        _field_qual_list_destroy(&(stage_fc->_field_table_doublewide_fpf[idx]));
        _field_qual_list_destroy(&(stage_fc->_field_table_extn[idx]));

        stage_fc->_field_table_fpf0[idx] = NULL;
        stage_fc->_field_table_fpf1[idx] = NULL;
        stage_fc->_field_table_fpf2[idx] = NULL;
        stage_fc->_field_table_fpf3[idx] = NULL;
        stage_fc->_field_table_fpf4[idx] = NULL;
        stage_fc->_field_table_doublewide_fpf[idx] = NULL;
        stage_fc->_field_table_extn[idx] = NULL;
    }
    _field_qual_list_destroy(&(stage_fc->_field_table_fixed[0]));
    stage_fc->_field_table_fixed[0] = NULL;

    if (stage_fc->_field_sel_f0 != NULL) {
        sal_free(stage_fc->_field_sel_f0);
        stage_fc->_field_sel_f0 = NULL;
    }
    if (stage_fc->_field_sel_f1 != NULL) {
        sal_free(stage_fc->_field_sel_f1);
        stage_fc->_field_sel_f1 = NULL;
    }
    if (stage_fc->_field_sel_f2 != NULL) {
        sal_free(stage_fc->_field_sel_f2);
        stage_fc->_field_sel_f2 = NULL;
    }
    if (stage_fc->_field_sel_f3 != NULL) {
        sal_free(stage_fc->_field_sel_f3);
        stage_fc->_field_sel_f3 = NULL;
    }
    if (stage_fc->_field_sel_f4 != NULL) {
        sal_free(stage_fc->_field_sel_f4);
        stage_fc->_field_sel_f4 = NULL;
    }
    if (stage_fc->_field_sel_doublewide != NULL) {
        sal_free(stage_fc->_field_sel_doublewide);
        stage_fc->_field_sel_doublewide = NULL;
    }
    if (stage_fc->_field_sel_extn != NULL) {
        sal_free(stage_fc->_field_sel_extn);
        stage_fc->_field_sel_extn = NULL;
    }
    if (stage_fc->_field_sel_fixed != NULL) {
        sal_free(stage_fc->_field_sel_fixed);
        stage_fc->_field_sel_fixed = NULL;
    }

    /* Free qualifiers arrays. */ 
    BCM_IF_ERROR_RETURN(_field_stage_qualifiers_free(unit, stage_fc));

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stage_fpf_init
 *
 * Purpose:
 *     Allocate and initialize memory for qualifier and qset table. 
 *
 * Parameters:
 *     unit     - (IN)     BCM unit
 *     stage_fc - (IN/OUT) Stage to be initialize.
 * 
 * Returns:
 *     BCM_E_NONE  - Success
 *     BCM_E_XXX   - From table read/write
 */
STATIC int
_field_stage_fpf_init(int unit, _field_stage_t *stage_fc)
{
    int qset_sz;      /* Qset table size      */
    int qset_tab_sz;  /* Qualifier table size */

    qset_tab_sz = sizeof(_qual_info_t *) * FPF_SZ_MAX;
    sal_memset(stage_fc->_field_table_fpf0, 0, qset_tab_sz);
    sal_memset(stage_fc->_field_table_fpf1, 0, qset_tab_sz);
    sal_memset(stage_fc->_field_table_fpf2, 0, qset_tab_sz);
    sal_memset(stage_fc->_field_table_fpf3, 0, qset_tab_sz);
    sal_memset(stage_fc->_field_table_fpf4, 0, qset_tab_sz);
    sal_memset(stage_fc->_field_table_doublewide_fpf, 0, qset_tab_sz);
    sal_memset(stage_fc->_field_table_extn, 0, qset_tab_sz);
    sal_memset(stage_fc->_field_table_fixed, 0, sizeof(_qual_info_t *));

    /* Allocate the Qset table. */
    qset_sz = sizeof(bcm_field_qset_t) * FPF_SZ_MAX; 
    stage_fc->_field_sel_f0 = sal_alloc(qset_sz, "FPF0 Table");
    stage_fc->_field_sel_f1 = sal_alloc(qset_sz, "FPF1 Table");
    stage_fc->_field_sel_f2 = sal_alloc(qset_sz, "FPF2 Table");
    stage_fc->_field_sel_f3 = sal_alloc(qset_sz, "FPF3 Table");
    stage_fc->_field_sel_f4 = sal_alloc(qset_sz, "FPF4 Table");
    stage_fc->_field_sel_doublewide = sal_alloc(qset_sz, "Doublewide Table");
    stage_fc->_field_sel_extn = sal_alloc(qset_sz, "FPFextn Table");
    stage_fc->_field_sel_fixed = sal_alloc(sizeof(bcm_field_qset_t), 
                                                         "FPF Fixed Table");
    sal_memset(&stage_fc->_field_supported_qset, 0, sizeof(bcm_field_qset_t));

    if (stage_fc->_field_sel_f0 == NULL ||
        stage_fc->_field_sel_f1 == NULL ||
        stage_fc->_field_sel_f2 == NULL ||
        stage_fc->_field_sel_f3 == NULL ||
        stage_fc->_field_sel_f4 == NULL ||
        stage_fc->_field_sel_doublewide == NULL ||
        stage_fc->_field_sel_extn == NULL ||
        stage_fc->_field_sel_fixed == NULL) {
        _field_stage_fpf_destroy(unit, stage_fc);
        FP_ERR(("FP(unit %d) Error: Allocation failure for FPF Table.\n", unit));
        return (BCM_E_MEMORY);
    }

    /* Initialize the Qset table. */
    sal_memset(stage_fc->_field_sel_f0, 0, qset_sz);
    sal_memset(stage_fc->_field_sel_f1, 0, qset_sz);
    sal_memset(stage_fc->_field_sel_f2, 0, qset_sz);
    sal_memset(stage_fc->_field_sel_f3, 0, qset_sz);
    sal_memset(stage_fc->_field_sel_f4, 0, qset_sz);
    sal_memset(stage_fc->_field_sel_doublewide, 0, qset_sz);
    sal_memset(stage_fc->_field_sel_extn, 0, qset_sz);
    sal_memset(stage_fc->_field_sel_fixed, 0, sizeof(bcm_field_qset_t));

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_qual_add
 * Purpose:
 *     Install field selector to selectors table. 
 *
 * Parameters:
 *   fpf_info - (IN) FPF memory, field, qual table and selector table info.
 *   qid      - (IN) Qualifier id.
 *   offset   - (IN) Qualifier offset.
 *   width    - (IN) Qualifier width. 
 *   code     - (IN) FPF table index.  
 * Returns: 
 *     BCM_E_XXX
 */
int
_field_qual_add (_field_fpf_info_t *fpf_info, int qid, 
                 int offset, int width, int code)
{
    _qual_info_t     *fq_p;

    /* Input parameters check. */
    if ((code >= FPF_SZ_MAX) || (NULL == fpf_info)) {
         return (BCM_E_PARAM);
    }

    /* Allocate qualifier info. */
    fq_p = sal_alloc(sizeof(_qual_info_t), "Qualifier Info");
    if (NULL == fq_p) {   
        return (BCM_E_MEMORY);
    }

    /* Set qualifier data. */
    _FP_QUAL_INFO_SET(qid, fpf_info->field, offset, width, fq_p);

    /* Insert qual_table */
    fq_p->next = fpf_info->qual_table[code];                        
    fpf_info->qual_table[code] = fq_p;

    /* Insert qual_table */
    BCM_FIELD_QSET_ADD_INTERNAL(fpf_info->sel_table[code], qid);

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_group_slice_count_get
 * Purpose:
 *     Retrieve number of slices group occupies
 * Parameters:
 *     flags -(IN) Group flags.
 *     count -(OUT)Slice count (1-3).
 * Returns:
 *    BCM_E_XXX
 */
int
_field_group_slice_count_get(uint32 flags, int *count)
{

    if (NULL == count) {
        return (BCM_E_PARAM);
    }

    if (flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
        *count = 3;
    } else if (flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
        *count = 2;
    } else {
        *count = 1;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_qual_offset_get
 * Purpose:
 *     Retrieve qualifier offsets
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     f_ent    - (IN) Field entry structure.
 *     qid      - (IN) Qualifier id.
 *     offset   - (OUT) Qualifier offset and width.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_qual_offset_get(int unit, _field_entry_t *f_ent, int qid, 
                       _bcm_field_qual_offset_t **offset)
{
    _bcm_field_group_qual_t *q_arr;    /* Qualifiers array.          */
    _field_group_t          *fg;       /* Field group structure.     */
    uint8                   entry_part;/* Wide entry part number.    */
    int                     rv;        /* Operation return status.   */  
    int                     idx;       /* Entry qualifiers iterator. */

    FP_VVERB(("_field_qual_offset_get\n"));

    /* Input parameters check. */
    if ((NULL == offset) || (NULL == f_ent)) {
        return (BCM_E_PARAM); 
    }

    /* Get entry group. */
    fg = f_ent->group;

    if (0 == BCM_FIELD_QSET_TEST(fg->qset, qid)) {
        /* Only qualifiers that were explicitly requested may be used */
        FP_ERR(("FP(unit %d) Error: qual=%s not in group=%d Qset\n", unit,
                _field_qual_name(qid), f_ent->group->gid));
        return (BCM_E_PARAM);
    }

    /* Get field entry part where qualifier resides. */
    rv = _bcm_field_entry_flags_to_tcam_part (f_ent->flags, fg->flags,
                                              &entry_part);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier information. */
    q_arr = fg->qual_arr + entry_part; 
    for (idx = 0; idx < q_arr->size; idx++) {
        if (qid == q_arr->qid_arr[idx]) {
            *offset = q_arr->offset_arr + idx;
            break;
        }
    }

    if (idx == q_arr->size) {
        *offset = NULL;
        return (BCM_E_NOT_FOUND);
    }
    return (BCM_E_NONE);
}


/*
 * Function:
 *     _field_group_qualifiers_free
 * Purpose:
 *     Free group qualifiers array. 
 * Parameters:
 *     fg   - (IN) Field group structure. 
 *     idx  - (IN) Entry part.
 * Returns:
 *     void
 * Note:
 */
int
_bcm_field_group_qualifiers_free(_field_group_t *fg, int idx)
{
    _bcm_field_group_qual_t *q_arr;       /* Qualifiers array.        */

    /* Input parameters check. */
    if ((NULL == fg) || (idx < 0) || (idx >= _FP_MAX_ENTRY_WIDTH)) {
        return BCM_E_PARAM;
    }

    q_arr = fg->qual_arr + idx;

    /* Free qualifiers arrays. */ 
    if (NULL != q_arr->qid_arr) {
        sal_free(q_arr->qid_arr);
        q_arr->qid_arr = NULL;
    }
    if (NULL != q_arr->offset_arr) {
        sal_free(q_arr->offset_arr);
        q_arr->offset_arr = NULL;
    }
    /* Reset arrays size. */
    q_arr->size = 0;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_qual_list_append
 * Purpose:
 *     Append a copy of a qualify info linked list.
 * Parameters:
 *     fg         - (IN) Field group structure. 
 *     entry_part - (IN) Field entry part. 
 *     fq_src     - (IN) Copy source list.  
 *     offset     - (IN) Offset within FPFx field.
 * Returns:
 *     BCM_E_NONE
 * Note:
 */
int
_bcm_field_qual_list_append(_field_group_t *fg, uint8 entry_part,
                            _qual_info_t *fq_src, int offset)
{
    _bcm_field_qual_offset_t *q_offset_arr;  /* Qualifier offsets array. */
    _bcm_field_group_qual_t  *q_arr;         /* Qualifiers array.        */
    _qual_info_t *fq_src_iter;               /* Qualifier list iterator. */
    uint16 *qid_arr;                         /* Qualifier id array.      */
    int    size;                             /* Qualifiers array size.   */

    /* Input parameters check. */ 
    if ((NULL == fg) || (NULL == fq_src) || 
        (entry_part >= _FP_MAX_ENTRY_WIDTH)) {
        return (BCM_E_PARAM);
    }

    /* Initialization. */
    qid_arr = NULL;
    q_offset_arr = NULL;
    q_arr = fg->qual_arr + entry_part;

    /* Count number of group qualifiers. */
    fq_src_iter = fq_src;
    size = 0;

    while (NULL != fq_src_iter) {
        if (0 == BCM_FIELD_QSET_TEST(fg->qset, fq_src_iter->qid)) {
            fq_src_iter = fq_src_iter->next;
            continue;
        }
        size++;
        fq_src_iter = fq_src_iter->next;
    }

    if (0 == size) {
        return (BCM_E_NONE);
    }
   
    size += q_arr->size;

    /* Allocate qualifiers id and offsets array. */
    _FP_XGS3_ALLOC(qid_arr, size * sizeof (uint16), "Group qual id");
    if (NULL == qid_arr) {
        return (BCM_E_MEMORY);
    }
    
    _FP_XGS3_ALLOC(q_offset_arr, size * sizeof (_bcm_field_qual_offset_t), 
                   "Group qual offset");
    if (NULL == q_offset_arr) {
        sal_free (qid_arr);
        return (BCM_E_MEMORY);
    }
    
    /* Copy original qualifiers array if any. */
    if (q_arr->size) {
        sal_memcpy(qid_arr, q_arr->qid_arr, q_arr->size * sizeof (uint16));
        sal_memcpy(q_offset_arr, q_arr->offset_arr, q_arr->size * sizeof (_bcm_field_qual_offset_t));
        sal_free (q_arr->qid_arr);
        sal_free (q_arr->offset_arr);
    }

    /* Copy qualifiers id and offsets. */
    q_arr->qid_arr = qid_arr;
    q_arr->offset_arr = q_offset_arr;
    fq_src_iter = fq_src;
    while (NULL != fq_src_iter) {
        if (0 == BCM_FIELD_QSET_TEST(fg->qset, fq_src_iter->qid)) {
            fq_src_iter = fq_src_iter->next;
            continue;
        }
        q_arr->qid_arr[q_arr->size] = fq_src_iter->qid;
        q_arr->offset_arr[q_arr->size].offset = fq_src_iter->offset + offset;
        q_arr->offset_arr[q_arr->size].width = fq_src_iter->width;
        q_arr->offset_arr[q_arr->size].field = fq_src_iter->fpf;
        q_arr->size++;
        fq_src_iter = fq_src_iter->next;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_entry_tcam_memory_info_get
 * Purpose:
 *     Get TCAM memory and field names for specific entry. 
 * Parameters:
 *     unit  - (IN)  BCM device number. 
 *     f_ent - (IN)  Field entry.
 *     tcam  - (OUT) TCAM memory info.  
 * Returns:
 *     BCM_E_XXX 
 */
STATIC int
_field_entry_tcam_memory_info_get(int unit, _field_entry_t *f_ent, 
    _field_tcam_mem_info_t *tcam, int ipbm_overlay)
{

    /* Input parameters check. */
    if ((NULL == f_ent)  || (NULL == tcam)) {
        return (BCM_E_PARAM);
    }

    /* Get tcam memory and field name. */
#if defined(BCM_EASYRIDER_SUPPORT) 
    if (SOC_IS_EASYRIDER(unit)) {
        tcam->key_field = KEYf;
        tcam->mask_field = MASKf;
        tcam->memory = FP_INTERNALm;
    }
#endif /* BCM_EASYRIDER_SUPPORT */

#if defined(BCM_FIREBOLT_SUPPORT) 

#if defined(BCM_HURRICANE_SUPPORT) 
        if (SOC_IS_HURRICANE(unit)) {
                tcam->key_field = DATAf;
                tcam->mask_field = DATA_MASKf;
                tcam->memory = FP_TCAMm;
        } else
#endif /* BCM_HURRICANE_SUPPORT */
    if (SOC_IS_FBX(unit)) {
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
        if (soc_feature(unit, soc_feature_field_multi_stage)) {
            if ((_BCM_FIELD_STAGE_INGRESS == f_ent->group->stage_id)) {
                tcam->memory = FP_TCAMm;
                if (SOC_IS_TD_TT(unit))
                {
                    tcam->key_field = KEYf;
                    tcam->mask_field = MASKf;

                    if (ipbm_overlay)
                    {
                        tcam->memory = FP_GM_FIELDSm;
                    }
                } else if (1 == ipbm_overlay &&
                            SOC_IS_TRIUMPH2(unit)) {
                    tcam->key_field = IPBMf;
                    tcam->mask_field = IPBM_MASKf;
                    tcam->memory = FP_GLOBAL_MASK_TCAMm;
                } else if ((SOC_IS_TRX(unit)) ||
                    (f_ent->flags & _FP_ENTRY_SECOND_HALF)) {
                    tcam->key_field = DATAf;
                    tcam->mask_field = DATA_MASKf;
                } else {
                    tcam->key_field = KEYf;
                    tcam->mask_field = MASKf;
                }
            }
            if (_BCM_FIELD_STAGE_EGRESS == f_ent->group->stage_id) {
                tcam->memory = EFP_TCAMm;
                tcam->key_field = KEYf;
                tcam->mask_field = KEY_MASKf;
            } else if (_BCM_FIELD_STAGE_LOOKUP== f_ent->group->stage_id) {
                tcam->memory = VFP_TCAMm;
                tcam->key_field = KEYf;
                tcam->mask_field = MASKf;
            } 
        } else 
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */ 
        {
            tcam->key_field = KEYf;
            tcam->mask_field = MASKf;
            tcam->memory =  FP_TCAMm;
        } 
    }
#endif /* BCM_FIREBOLT_SUPPORT */
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_qual_tcam_key_mask_free
 * Purpose:
 *     Free tcam key/mask buffers.
 * Parameters:
 *     unit  - (IN)     BCM device number. 
 *     f_ent - (IN/OUT) Field entry.
 * Returns:
 *     BCM_E_XXX 
 */
int
_bcm_field_qual_tcam_key_mask_free(int unit, _field_entry_t *f_ent)
{
    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    if (NULL != f_ent->tcam.key) {
        sal_free(f_ent->tcam.key);
        f_ent->tcam.key = NULL;
    }
    if (NULL != f_ent->tcam.mask) {
        sal_free(f_ent->tcam.mask);
        f_ent->tcam.mask = NULL;
    }
    if (NULL != f_ent->tcam.key_hw) {
        sal_free(f_ent->tcam.key_hw);
        f_ent->tcam.key_hw = NULL;
    }
    if (NULL != f_ent->tcam.mask_hw) {
        sal_free(f_ent->tcam.mask_hw);
        f_ent->tcam.mask_hw = NULL;
    }
    if (NULL != f_ent->extra_tcam.key) {
        sal_free(f_ent->extra_tcam.key);
        f_ent->extra_tcam.key = NULL;
    }
    if (NULL != f_ent->extra_tcam.mask) {
        sal_free(f_ent->extra_tcam.mask);
        f_ent->extra_tcam.mask = NULL;
    }
    if (NULL != f_ent->extra_tcam.key_hw) {
        sal_free(f_ent->extra_tcam.key_hw);
        f_ent->extra_tcam.key_hw = NULL;
    }
    if (NULL != f_ent->extra_tcam.mask_hw) {
        sal_free(f_ent->extra_tcam.mask_hw);
        f_ent->extra_tcam.mask_hw = NULL;
    }
    return (BCM_E_NONE);
}

int _field_qual_tcam_key_mask_get(int unit, _field_entry_t *f_ent,
    _field_tcam_t *tcam, int ipbm_overlay)
{
    uint32 tcam_entry[SOC_MAX_MEM_FIELD_WORDS];
    _field_tcam_mem_info_t tcam_info = { 0 };
    int tcam_idx;
    int rv;
    int key_size;

    /* Get TCAM memory and Fields information. */

    BCM_IF_ERROR_RETURN(_field_entry_tcam_memory_info_get(unit, f_ent,
        &tcam_info, ipbm_overlay));

    if (!SOC_MEM_FIELD_VALID(unit, tcam_info.memory, tcam_info.key_field)) {
        return (BCM_E_INTERNAL);
    }
    /* Key size in bits. */
    key_size = soc_mem_field_length(unit, tcam_info.memory,
        tcam_info.key_field);
    /* Convert to bytes - full number of words alligned. */
    key_size = (((key_size >> 5) + 1) << 2);


    /* Allocate and zero memory for tcam image.*/
    tcam->key  = sal_alloc(key_size, "field_entry_tcam_key");
    tcam->mask = sal_alloc(key_size, "field_entry_tcam_mask");
    if ((NULL == tcam->key) || (NULL == tcam->mask)) {
        FP_ERR(("FP(unit %d) Error: allocation failure for field_entry tcam\n", unit));
        if (tcam->key) sal_free(tcam->key); 
        if (tcam->mask) sal_free(tcam->mask); 
        return (BCM_E_MEMORY);
    }
    sal_memset(tcam->key, 0, key_size);
    sal_memset(tcam->mask, 0, key_size);
    tcam->key_size = key_size;

    /* Read entry from HW if it was installed previously. */
    if(f_ent->flags & _FP_ENTRY_INSTALLED) {
        rv = _bcm_field_entry_tcam_idx_get(unit, f_ent, &tcam_idx);
        if (BCM_FAILURE(rv)) {
            if (tcam->key) sal_free(tcam->key); 
            if (tcam->mask) sal_free(tcam->mask); 
            tcam->mask = tcam->key = NULL;
            return (rv);
        }
        rv = soc_mem_read(unit, tcam_info.memory, MEM_BLOCK_ANY, 
                          tcam_idx, tcam_entry);
        if (BCM_FAILURE(rv)) {
            if (tcam->key) sal_free(tcam->key); 
            if (tcam->mask) sal_free(tcam->mask); 
            tcam->mask = tcam->key = NULL;
            return (rv);
        }
        soc_mem_field_get(unit, tcam_info.memory, tcam_entry, 
                          tcam_info.key_field, tcam->key);
        soc_mem_field_get(unit, tcam_info.memory, tcam_entry, 
                          tcam_info.mask_field, tcam->mask);
        if (SOC_MEM_FIELD_VALID(unit, tcam_info.memory, F4f)) {
            soc_mem_field_get(unit, tcam_info.memory, tcam_entry, 
                              F4f, &tcam->f4);
            soc_mem_field_get(unit, tcam_info.memory, tcam_entry, 
                              F4_MASKf, &tcam->f4_mask);
        }
    }

    return BCM_E_NONE;
}

/*
 * Function:
 *     _bcm_field_qual_tcam_key_mask_get
 * Purpose:
 *     Allocate & read from hw tcam key/mask image. 
 * Parameters:
 *     unit  - (IN)     BCM device number. 
 *     f_ent - (IN/OUT) Field entry.
 * Returns:
 *     BCM_E_XXX 
 */
int
_bcm_field_qual_tcam_key_mask_get(int unit, _field_entry_t *f_ent)
{
    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }


    if (f_ent->flags & _FP_ENTRY_USES_IPBM_OVERLAY) {
        if (NULL == f_ent->extra_tcam.key) {
            BCM_IF_ERROR_RETURN(_field_qual_tcam_key_mask_get(unit, f_ent,
                &f_ent->extra_tcam, 1));
        }
    }

    /* Check if tcam info already present. */
    if (NULL != f_ent->tcam.key) {
        return (BCM_E_NONE);
    }

    if (_BCM_FIELD_STAGE_EXTERNAL == f_ent->fs->stage_id) {
#if defined(BCM_TRIUMPH_SUPPORT)
        if (SOC_IS_TRIUMPH(unit) || SOC_IS_TRIUMPH2(unit)) {
            return _bcm_field_tr_external_tcam_key_mask_get(unit, f_ent); 
        }
#endif /* BCM_TRIUMPH_SUPPORT */
    }

    BCM_IF_ERROR_RETURN(_field_qual_tcam_key_mask_get(unit, f_ent,
        &f_ent->tcam, 0));

    return (BCM_E_NONE);
}


/*
 * Function:
 *     _field_qual_value_set
 *
 * Purpose:
 *     Set a qualifier field from the designated data and mask arrays.
 *
 * Parameters:
 *     unit    - (IN) BCM devices number 
 *     qi      - (IN) Qualifier offset inside tcam.
 *     f_ent   - (IN) Field entry descriptor.
 *     p_data  - (IN) Inserted data.
 *     p_mask  - (IN) Data mask.
 * Returns:
 *     BCM_E_XXX 
 */
STATIC int
_field_qual_value_set(int unit, _qual_info_t *qi, 
                      _field_entry_t *f_ent,
                      uint32 *p_data, uint32 *p_mask, int ipbm_overlay)
{
    uint32              u32_mask, *p_fn_data, *p_fn_mask;
    int                 idx, wp, bp, len;

#define DATA_TOO_BIG_FOR_FIELD ((p_data[idx] & ~u32_mask) != 0)
    wp = qi->offset / 32;
    bp = qi->offset & (32 - 1);
    idx = 0;
    p_fn_data = p_fn_mask = NULL;

    FP_VVERB(("FP(unit %d) vverb: qi={offset=%d, width=%d}, ipbm_overlay=%d, data=0x%08x, mask=0x%08x\n", 
              unit, qi->offset, qi->width, ipbm_overlay, *p_data, *p_mask));

    BCM_IF_ERROR_RETURN(_bcm_field_qual_tcam_key_mask_get(unit, f_ent));

    switch (qi->fpf) {
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
      case DATAf:
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
      case KEYf:
#if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT)
          if (ipbm_overlay) {
              p_fn_data = f_ent->extra_tcam.key;
              p_fn_mask = f_ent->extra_tcam.mask;
          } else
#endif /* BCM_TRIDENT_SUPPORT */
          {
              p_fn_data = f_ent->tcam.key;
              p_fn_mask = f_ent->tcam.mask;
          }

          break;
#ifdef BCM_FIREBOLT_SUPPORT
      case F4f:
          p_fn_data = &f_ent->tcam.f4;
          p_fn_mask = &f_ent->tcam.f4_mask;
          break;
#endif /* BCM_FIREBOLT_SUPPORT */
      default:
          FP_ERR(("FP(unit %d) Error: Bad TCAM field=%#05x\n", unit, qi->fpf));
          return (BCM_E_INTERNAL);
    };

    for (len = qi->width; len > 0; len -= 32) {
        if (bp) {
            if (len < 32) {
                u32_mask = (1 << len) - 1;
                /* Chop mask to fit mask field. */
                p_mask[idx] &= u32_mask;
                if (DATA_TOO_BIG_FOR_FIELD) {
                    FP_ERR(("FP(unit %d) Error: data=%#x ", unit, *p_data));
                    FP_ERR(("or mask=%#x too big for field\n", *p_mask));
                    return (BCM_E_PARAM);
                }
            } else {
                u32_mask = 0xffffffff;
            }

            p_fn_data[wp] &= ~(u32_mask << bp);
            p_fn_data[wp] |= p_data[idx] << bp;

            p_fn_mask[wp] &= ~(u32_mask << bp);
            p_fn_mask[wp++] |= p_mask[idx] << bp;

            p_fn_data[wp] &= ~(u32_mask >> (32 - bp));
            p_fn_data[wp] |= p_data[idx] >> (32 - bp) & ((1 << bp) - 1);

            p_fn_mask[wp] &= ~(u32_mask >> (32 - bp));
            p_fn_mask[wp] |= p_mask[idx] >> (32 - bp) & ((1 << bp) - 1);
        } else {
            if (len < 32) {
                u32_mask = (1 << len) - 1;
                /* Chop mask to fit mask field. */
                p_mask[idx] &= u32_mask;
                if (DATA_TOO_BIG_FOR_FIELD) {
                    FP_ERR(("FP(unit %d) Error: data=%#x or mask=%#x " 
                            "too big for field\n",
                            unit, *p_data, *p_mask));
                    return (BCM_E_PARAM);
                }
                p_fn_data[wp] &= ~u32_mask;
                p_fn_data[wp] |= p_data[idx];
                p_fn_mask[wp] &= ~u32_mask;
                p_fn_mask[wp++] |= p_mask[idx];
            } else {
                p_fn_data[wp] = p_data[idx];
                p_fn_mask[wp++] = p_mask[idx];
            }
        }

        idx++;
    }

    f_ent->flags |= _FP_ENTRY_DIRTY;
    f_ent->flags &= ~(_FP_ENTRY_ACTION_ONLY_DIRTY);
    
    return (BCM_E_NONE);
}
#undef DATA_TOO_BIG_FOR_FIELD
#undef MASK_TOO_BIG_FOR_FIELD

/*
 * Function:
 *     _field_qual_value_get
 *
 * Purpose:
 *     Retrieve a qualifier value from the designated data/mask
 *     field pair, returning them to *p_data and *p_mask.
 *
 * Returns:
 *     BCM_E_NONE - Success
 */
STATIC int
_field_qual_value_get(int unit, _qual_info_t *qi, _field_entry_t *f_ent,
                      uint32 *p_data, uint32 *p_mask, int ipbm_overlay)
{
    uint32              *p_fn_data, *p_fn_mask;
    int                 idx, wp, bp, len;

    /* Input parameters check. */
    if ((NULL == f_ent) || (NULL == p_data) ||
        (NULL == qi) || (NULL == p_mask)) {
        return (BCM_E_PARAM);
    }

    wp = qi->offset / 32;
    bp = qi->offset & (32 - 1);
    idx = 0;
    p_fn_data = p_fn_mask = NULL;
    
    BCM_IF_ERROR_RETURN(_bcm_field_qual_tcam_key_mask_get(unit, f_ent));

    switch (qi->fpf) {
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
        case DATAf:
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
        case KEYf:
#if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT)
            if (ipbm_overlay) {
                p_fn_data = f_ent->extra_tcam.key;
                p_fn_mask = f_ent->extra_tcam.mask;
            } else
#endif /* BCM_TRIDENT_SUPPORT */
            {
                p_fn_data = f_ent->tcam.key;
                p_fn_mask = f_ent->tcam.mask;
            }
            break;
#ifdef BCM_FIREBOLT_SUPPORT
        case F4f:
            p_fn_data = &f_ent->tcam.f4;
            p_fn_mask = &f_ent->tcam.f4_mask;
            break;
#endif /* BCM_FIREBOLT_SUPPORT */
        default:
            FP_ERR(("FP(unit %d) Error: Bad TCAM field=%#05x\n", unit, qi->fpf));
            return (BCM_E_INTERNAL);
    };

    for (len = qi->width; len > 0; len -= 32) {
        if ((NULL == p_fn_data) || (NULL == p_fn_mask)) {
            /* 
             * IPBM Overlay qualifier set in the group but 
             * not qualified for this entry.
             */
            p_data[idx] = 0x0;
            p_mask[idx] = 0x0;
        } else {
            if (bp) {
                p_data[idx] = (p_fn_data[wp] >> bp) & ((1 << (32 - bp)) - 1);
                p_mask[idx] = (p_fn_mask[wp++] >> bp) & ((1 << (32 - bp)) - 1);
                p_data[idx] |= p_fn_data[wp] << (32 - bp);
                p_mask[idx] |= p_fn_mask[wp] << (32 - bp);
            } else {
                p_data[idx] = p_fn_data[wp];
                p_mask[idx] = p_fn_mask[wp++];
            }
        }

        if (len < 32) {
            p_data[idx] &= ((1 << len) - 1);
            p_mask[idx] &= ((1 << len) - 1);
        }

        idx++;
    }
    
    return (BCM_E_NONE);
}


/*
 * Function:
 *     _field_qualifier_partial_data_get
 * Purpose:
 *     Get a portion of a uint32 array
 * Parameters:
 *     in_data   - uint32 array
 *     start_pos - starting bit postion in above array requested (base-0)
 *     len       - length of data requested (in bits)
 *     out_data  - uint32 array of in_data from start_pos to start_pos + len 
 * Returns:
 *     BCM_E_XXX
 * Notes: 
 *     - Calculate the word in in_data where start_pos occurs
 *     - Calculate the bit position in above word where start_pos occurs
 *     - Iterate:
 *         - Get upper half of word (from bit position to end of word)
 *         - Get remainder portion from next word
 *             - If required: bit postion not 0 (start_pos not a multiple of 32)
 *             - If present
 *         - These two together form one word of out_data
 *         - Go to next word.
 *     - Mask the higher (extra) bits in last word of out_data
 *
 *     - max_size is set to 16 (128 bits) as this is used for Ip6 and DstMac
 */
STATIC int 
_field_qualifier_partial_data_get(uint32 *in_data, uint8 start_pos, 
                                  uint8 len, uint32 *out_data)
{
    int current_word, bit_pos, result_word;
    int i;
    int max_size = 16;

    /* Input parameters check. */
    if ((NULL == in_data) || (NULL == out_data) || 
        ((start_pos + len) > 128)) {
        return (BCM_E_UNAVAIL);
    }

    current_word = start_pos / 32;
    bit_pos = start_pos - current_word * 32;

    sal_memset(out_data, 0, max_size);

    for (i = 0, result_word = 0; i < len; 
         i += 32, current_word++, result_word++) {

        out_data[result_word] = in_data[current_word] >> bit_pos;

        if ((bit_pos != 0) && ((bit_pos + (len - i)) > 32)) {
            out_data[result_word] |= (in_data[current_word + 1] << (32 - bit_pos));
        }
    }
    /* This check may be redundant as -1 = 0xffffffff */
    if (i != len) {
        i -= 32;
        out_data[result_word - 1] &= ((1 << (len - i)) - 1);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_qualifier_partial_data_set
 * Purpose:
 *     Set a portion of a uint32 array
 * Parameters:
 *     in_data   - uint32 array
 *     start_pos - starting bit postion in above array requested (base-0)
 *     len       - length of data requested (in bits)
 *     out_data  - uint32 array of in_data from start_pos to start_pos + len 
 * Returns:
 *     none
 * Notes: 
 *     - Calculate the word in out_data where start_pos occurs
 *     - Calculate the bit position in above word where start_pos occurs
 *     - Iterate:
 *         - Or upper half of word (from bit position to end of word)
 *         - Set remainder portion to the next word
 *             - If required: bit postion not 0 (start_pos not a multiple of 32)
 *             - If present
 *         - These two together form one word of out_data
 *         - Go to next word.
 *     - Mask the higher (extra) bits in last word of out_data
 *
 *     - max_size is set to 16 (128 bits) as this is used for Ip6 and DstMac
 *
 * NOTES
 * 1. Assumes that there are no extra bits in in_data, i.e. all of in_data is
 *    copied.
 * 2. Assumes that out_data has been zeroed-out.
 */
STATIC int 
_field_qualifier_partial_data_set(uint32 *in_data, uint8 start_pos, 
                                  uint8 len, uint32 *out_data)
{
    int current_word, bit_pos, result_word;
    int i;

    /* Input parameters check. */
    if ((NULL == in_data) || (NULL == out_data) || 
        ((start_pos + len) > 128)) {
        return (BCM_E_UNAVAIL);
    }

    result_word = start_pos / 32;
    bit_pos = start_pos - result_word * 32;

    for (i = 0, current_word= 0; i < len; 
         i += 32, current_word++, result_word++) {

        out_data[result_word] |= (in_data[current_word] <<  bit_pos);

        if ((bit_pos != 0) && ((bit_pos + (len - i)) > 32)) {
            out_data[result_word + 1] |= (in_data[current_word] >> (32 - bit_pos));
        }
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_qual_part_value_get
 *
 * Purpose:
 *     Get a qualifier field from the designated data and mask arrays.
 *
 * Parameters:
 *     unit     - (IN) BCM devices number 
 *     q_offset - (IN) Qualifier offset inside tcam.
 *     f_ent    - (IN) Field entry descriptor.
 *     p_data   - (IN) Inserted data.
 *     p_mask   - (IN) Data mask.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_qual_part_value_get(int unit, _bcm_field_qual_offset_t *q_offset, 
                           uint8 qual_part, _field_entry_t *f_ent, 
                           _bcm_field_qual_data_t p_data, 
                           _bcm_field_qual_data_t p_mask)
{
    _qual_info_t qi;
    int rv;
    _bcm_field_qual_data_t data;
    _bcm_field_qual_data_t mask;
    int offset = 0;
    int ipbm_overlay = 0;

    /* Input parameters check. */
    if ((NULL == q_offset) || (NULL == f_ent) ||
        (NULL == p_data) || (NULL == p_mask)) {
        return (BCM_E_PARAM);
    }

    /* Primary offset handling. */
    sal_memset(&qi, 0, sizeof(_qual_info_t));

    _FP_QUAL_DATA_CLEAR(data);
    _FP_QUAL_DATA_CLEAR(mask);
    qi.fpf = q_offset->field;
    switch (qual_part) {
      case 0:
          qi.offset = q_offset->offset; 
          qi.width = q_offset->width; 
          break;
      case 1:
          offset = q_offset->width;
          qi.offset = q_offset->offset1; 
          qi.width = q_offset->width1; 
          break;
      case 2:
          offset = q_offset->width + q_offset->width1;
          qi.offset = q_offset->offset2; 
          qi.width = q_offset->width2; 
          break;
      default:
          return (BCM_E_INTERNAL);
    }

#if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT)
    /* 
     * 1. Check if the part goes into the IPBM TCAM.
     * 2. In slice Pairing mode, TCP control flag bits[5:0] are split between
     *    IFP_PAIRING_IPBM_F0:TCP_FN_5_1[5:1] and IFP_PAIRING_F1:TCP_FN_0[0]
     *    This special overlay case is handled here (1 == qual_part)...
     */
    if ((SOC_IS_TD_TT(unit) && q_offset->secondary && 
        ((qual_part == 0 && 1 != q_offset->width && 5 != q_offset->width1) ||
        (1 == qual_part && 1 == q_offset->width && 5 == q_offset->width1)))
        || (SOC_IS_TRIUMPH2(unit) && 1 == q_offset->secondary)) {
        ipbm_overlay = 1;
    }
#endif

    /* Read qualifier information from tcam.. */
    rv = _field_qual_value_get(unit, &qi, f_ent, data, mask, ipbm_overlay);
    BCM_IF_ERROR_RETURN(rv);

    /* Split primary portion of the qualifier. */
    rv = _field_qualifier_partial_data_set(data, offset,
                                            qi.width, p_data);
    BCM_IF_ERROR_RETURN(rv);
    rv = _field_qualifier_partial_data_set(mask, offset,
                                           qi.width, p_mask);
    BCM_IF_ERROR_RETURN(rv);

    return (BCM_E_NONE);
}


/*
 * Function:
 *     _bcm_field_qual_value_get
 *
 * Purpose:
 *     Get a qualifier field from the designated data and mask arrays.
 *
 * Parameters:
 *     unit     - (IN) BCM devices number 
 *     q_offset - (IN) Qualifier offset inside tcam.
 *     f_ent    - (IN) Field entry descriptor.
 *     p_data   - (IN) Inserted data.
 *     p_mask   - (IN) Data mask.
 *
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_qual_value_get(int unit, _bcm_field_qual_offset_t *q_offset, 
                          _field_entry_t *f_ent, _bcm_field_qual_data_t p_data, 
                          _bcm_field_qual_data_t p_mask)
{
    int rv;

    /* Input parameters check. */
    if ((NULL == q_offset) || (NULL == f_ent) ||
        (NULL == p_data) || (NULL == p_mask)) {
        return (BCM_E_PARAM);
    }

    _FP_QUAL_DATA_CLEAR(p_data);
    _FP_QUAL_DATA_CLEAR(p_mask);

    /* Primary offset handling. */
    if (q_offset->width) {
        rv = _field_qual_part_value_get(unit, q_offset, 0, f_ent, p_data, p_mask);
        BCM_IF_ERROR_RETURN(rv);
    }
    if (q_offset->width1) {
        rv = _field_qual_part_value_get(unit, q_offset, 1, f_ent, p_data, p_mask);
        BCM_IF_ERROR_RETURN(rv);
    }
    if (q_offset->width2) {
        rv = _field_qual_part_value_get(unit, q_offset, 2, f_ent, p_data, p_mask);
        BCM_IF_ERROR_RETURN(rv);
    }
    return (BCM_E_NONE);
}
/*
 * Function:
 *     _field_qual_part_value_set
 *
 * Purpose:
 *     Set a qualifier field from the designated data and mask arrays.
 *
 * Parameters:
 *     unit      - (IN) BCM devices number 
 *     q_offset  - (IN) Qualifier offset inside tcam.
 *     qual_part - (IN) Split qualifier part. 
 *     f_ent     - (IN) Field entry descriptor.
 *     p_data    - (IN) Inserted data.
 *     p_mask    - (IN) Data mask.
 *
 * Returns:
 *     BCM_E_XXX
 */
int
_field_qual_part_value_set(int unit, _bcm_field_qual_offset_t *q_offset, 
                               uint8 qual_part, _field_entry_t *f_ent, 
                               uint32 *p_data, uint32 *p_mask)
{
    uint32 data[4];
    uint32 mask[4];
    _qual_info_t qi;
    int offset = 0;
    int ipbm_overlay = 0;
    int rv;

    FP_VVERB(("_field_qual_part_value_set\n"));
    FP_VVERB(("_field_qual_part_value_set:data:%x mask:%x\n", *p_data, *p_mask));

    /* Input parameters check. */
    if ((NULL == q_offset) || (NULL == f_ent) ||
        (NULL == p_data) || (NULL == p_mask)) {
        return (BCM_E_PARAM);
    }

    /* Primary offset handling. */
    sal_memset(&qi, 0, sizeof(_qual_info_t));
    qi.fpf = q_offset->field;
    switch (qual_part) {
      case 0:
          qi.offset = q_offset->offset; 
          qi.width = q_offset->width; 
          break;
      case 1:
          offset = q_offset->width;
          qi.offset = q_offset->offset1; 
          qi.width = q_offset->width1; 
          break;
      case 2:
          offset = q_offset->width + q_offset->width1;
          qi.offset = q_offset->offset2; 
          qi.width = q_offset->width2; 
          break;
      default:
          return (BCM_E_INTERNAL);
    }

    /* Split primary portion of the qualifier. */
    rv = _field_qualifier_partial_data_get (p_data, offset,
                                            qi.width, data);
    BCM_IF_ERROR_RETURN(rv);
    rv = _field_qualifier_partial_data_get(p_mask, offset,
                                           qi.width, mask);
    BCM_IF_ERROR_RETURN(rv);

#if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT)
    /* 
     * 1. Check if the part goes into the IPBM TCAM.
     * 2. In slice Pairing mode, TCP control flag bits[5:0] are split between
     *    IFP_PAIRING_IPBM_F0:TCP_FN_5_1[5:1] and IFP_PAIRING_F1:TCP_FN_0[0]
     *    This special overlay case is handled here (1 == qual_part)...
     */
    if ((SOC_IS_TD_TT(unit) && q_offset->secondary &&
        ((qual_part == 0 && 1 != q_offset->width && 5 != q_offset->width1) ||
        (1 == qual_part && 1 == q_offset->width && 5 == q_offset->width1)))
        || (SOC_IS_TRIUMPH2(unit) && 1 == q_offset->secondary)) {
        ipbm_overlay = 1;
    }
#endif

    /* Program qualifier into tcam.. */
    rv = _field_qual_value_set(unit, &qi, f_ent, data, mask, ipbm_overlay);
    return (rv);
}

/*
 * Function:
 *     _field_entry_qualifier_key_get
 *
 * Purpose:
 *     Get qualifier match value and mask. 
 *
 * Parameters:
 *     unit      - BCM device number
 *     entry     - Entry id.
 *     qual_id   - qualifier id.
 *     q_data    - Qualifier data array. 
 *     q_mask    - Qualifier mask array.
 * Returns:
 *     Nothing.
 */
STATIC int
_field_entry_qualifier_key_get(int unit, 
                               bcm_field_entry_t entry, 
                               int qual_id, 
                               _bcm_field_qual_data_t q_data, 
                               _bcm_field_qual_data_t q_mask)
{
    uint8                     entry_part;  /* Tcam part number.             */
    _bcm_field_qual_offset_t  *q_offset;   /* Qualifier offset in the tcam. */
    int                       qual_idx;    /* Tcam part qualifiers iterator.*/ 
    _field_entry_t            *f_ent;      /* Field entry structure.        */
    _bcm_field_group_qual_t   *q_arr;      /* Tcam part Qualifiers array.   */
    _field_group_t            *fg;         /* Field group structure.        */
    int                       rv;          /* Operation return status.      */
    int                       free_tcam;   /* Free tcam key flag.           */


    _FP_QUAL_DATA_CLEAR(q_data);
    _FP_QUAL_DATA_CLEAR(q_mask);
    q_offset = NULL;
    free_tcam = FALSE;
    
    /* Get entry part that contains requested qualifier. */ 
    rv = _bcm_field_entry_qual_get(unit, entry, qual_id, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    fg = f_ent->group;

    /* Get entry tcam part number. */
    rv = _bcm_field_entry_flags_to_tcam_part (f_ent->flags, fg->flags, &entry_part);
    BCM_IF_ERROR_RETURN(rv);

    /*  Check if tcam data has to be freed at the end. */
    if (NULL == f_ent->tcam.key) {
        free_tcam = TRUE;
    }


    /* Get entry part qualifiers array. */
    q_arr = fg->qual_arr + entry_part;

    /* Search array by qualifier id to extract qualifier offsets in the tcam. */
    for (qual_idx = 0; qual_idx < q_arr->size; qual_idx++) {
        if ((uint16)qual_id == q_arr->qid_arr[qual_idx]) {
            q_offset = q_arr->offset_arr + qual_idx;
            break;
        }
    }
    if (NULL == q_offset) {
        return (BCM_E_INTERNAL);
    }

    /* Read tcam data/mask. */
    rv = _bcm_field_qual_tcam_key_mask_get(unit, f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* There is no value associated with zero width qualifiers (Stage, Ip4 etc)
     */
    if ((q_offset->width > 0) || (q_offset->width1 > 0)) {
        /* Read qualifier match value and mask. */
        rv = _bcm_field_qual_value_get(unit, q_offset, f_ent, q_data, q_mask);
    }

    if (free_tcam) {
        if (NULL != f_ent->tcam.key) {
            sal_free(f_ent->tcam.key);
            sal_free(f_ent->tcam.mask);
        }
        if (f_ent->flags & _FP_ENTRY_USES_IPBM_OVERLAY) {
            if (NULL != f_ent->extra_tcam.key) {
                sal_free(f_ent->extra_tcam.key);
                sal_free(f_ent->extra_tcam.mask);
            }
        }
        f_ent->tcam.key = f_ent->tcam.mask =
            f_ent->extra_tcam.key = f_ent->extra_tcam.mask = NULL;
        free_tcam = FALSE;
    }
    return (rv);
}

/*
 * Function:
 *     _bcm_field_entry_qualifier_uint8_get
 *
 * Purpose:
 *     Get qualifier match value and mask. 
 *
 * Parameters:
 *     unit      - BCM device number
 *     entry     - Entry id.
 *     qual_id   - qualifier id.
 *     data      - Qualifier data. 
 *     mask      - Qualifier mask.
 * Returns:
 *     Nothing.
 */
int 
_bcm_field_entry_qualifier_uint8_get(int unit, bcm_field_entry_t entry, 
                                 int qual_id, uint8 *data, 
                                 uint8 *mask)
{
    _bcm_field_qual_data_t     q_data;/* Qualifier match data.     */ 
    _bcm_field_qual_data_t     q_mask;/* Qualifier match mask.     */
    _field_control_t           *fc;   /* Field control structure.  */
    int                        rv;    /* Operation return status.  */
   /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_qualifier_key_get(unit, entry, qual_id, q_data, q_mask);

    FP_UNLOCK(fc);

    if (BCM_SUCCESS(rv)) {
        *data = (uint8)(q_data[0] & 0xff);
        *mask = (uint8)(q_mask[0] & 0xff);
    }
    return (rv);
}

/*
 * Function:
 *     _bcm_field_entry_qualifier_uint16_get
 *
 * Purpose:
 *     Get qualifier match value and mask. 
 *
 * Parameters:
 *     unit      - BCM device number
 *     entry     - Entry id.
 *     qual_id   - qualifier id.
 *     data      - Qualifier data. 
 *     mask      - Qualifier mask.
 * Returns:
 *     Nothing.
 */
int 
_bcm_field_entry_qualifier_uint16_get(int unit, bcm_field_entry_t entry, 
                                  int qual_id, uint16 *data, 
                                  uint16 *mask)
{
    _bcm_field_qual_data_t     q_data;/* Qualifier match data.     */ 
    _bcm_field_qual_data_t     q_mask;/* Qualifier match mask.     */
    _field_control_t           *fc;   /* Field control structure.  */
    int                        rv;    /* Operation return status.  */
   /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_qualifier_key_get(unit, entry, qual_id, q_data, q_mask);

    FP_UNLOCK(fc);

    if (BCM_SUCCESS(rv)) {
        *data = (uint16)(q_data[0] & 0xffff);
        *mask = (uint16)(q_mask[0] & 0xffff);
    }
    return (rv);
}

/*
 * Function:
 *     _bcm_field_entry_qualifier_uint32_get
 *
 * Purpose:
 *     Get qualifier match value and mask. 
 *
 * Parameters:
 *     unit      - BCM device number
 *     entry     - Entry id.
 *     qual_id   - qualifier id.
 *     data      - Qualifier data. 
 *     mask      - Qualifier mask.
 * Returns:
 *     Nothing.
 */
int 
_bcm_field_entry_qualifier_uint32_get(int unit, bcm_field_entry_t entry, 
                                  int qual_id, uint32 *data, 
                                  uint32 *mask)
{
    _bcm_field_qual_data_t     q_data;/* Qualifier match data.     */ 
    _bcm_field_qual_data_t     q_mask;/* Qualifier match mask.     */
    _field_control_t           *fc;   /* Field control structure.  */
    int                        rv;    /* Operation return status.  */

   /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_qualifier_key_get(unit, entry, qual_id, q_data, q_mask);

    FP_UNLOCK(fc);

    if (BCM_SUCCESS(rv)) {
        *data = q_data[0];
        *mask = q_mask[0];
    }
    return (rv);
}


/*
 * Function:
 *     _bcm_field_qual_value_set
 *
 * Purpose:
 *     Set a qualifier field from the designated data and mask arrays.
 *
 * Parameters:
 *     unit     - (IN) BCM devices number 
 *     q_offset - (IN) Qualifier offset inside tcam.
 *     f_ent    - (IN) Field entry descriptor.
 *     p_data   - (IN) Inserted data.
 *     p_mask   - (IN) Data mask.
 *
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_qual_value_set(int unit, _bcm_field_qual_offset_t *q_offset, 
                          _field_entry_t *f_ent, 
                          uint32 *p_data, uint32 *p_mask)
{
    int rv;

    FP_VVERB(("_bcm_field_qual_value_set\n"));

    /* Input parameters check. */
    if ((NULL == q_offset) || (NULL == f_ent) ||
        (NULL == p_data) || (NULL == p_mask)) {
        return (BCM_E_PARAM);
    }

    /* Primary offset handling. */

    if (q_offset->width > 0)
    {
        rv = _field_qual_part_value_set(unit, q_offset, 0, f_ent, p_data, p_mask);
        BCM_IF_ERROR_RETURN(rv);
    }

    if (q_offset->width1) {
        rv = _field_qual_part_value_set(unit, q_offset, 1, f_ent, p_data, p_mask);
        BCM_IF_ERROR_RETURN(rv);
    }
    if (q_offset->width2) {
        rv = _field_qual_part_value_set(unit, q_offset, 2, f_ent, p_data, p_mask);
        BCM_IF_ERROR_RETURN(rv);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_group_stage_get
 *
 * Purpose:
 *     Extract group pipeline stage from qualifiers set.
 *
 * Parameters:
 *     unit    - (IN)BCM device number.
 *     qset_p  - (IN)Group qualifiers set. 
 *     stage   - (OUT)Pipeline stage id.  
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_stage_get(int unit, bcm_field_qset_t *qset_p, 
                       _field_stage_id_t *stage)
{
    int stage_count = 0;   /* Check that only 1 stage specified in qset */

    /* Input parameters check. */
    if ((NULL == qset_p) || (NULL == stage)) {
        return (BCM_E_PARAM);
    }
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    /* Set stage based on qualifiers set. */
    if (soc_feature(unit, soc_feature_field_multi_stage)) {
        if(BCM_FIELD_QSET_TEST(*qset_p, bcmFieldQualifyStageIngress)) {
            *stage  = _BCM_FIELD_STAGE_INGRESS;
            stage_count++;
        }
        if(BCM_FIELD_QSET_TEST(*qset_p, bcmFieldQualifyStageEgress)) {
            *stage  = _BCM_FIELD_STAGE_EGRESS;
            stage_count++;
        }

        if(BCM_FIELD_QSET_TEST(*qset_p, bcmFieldQualifyStageLookup)) {
            *stage  = _BCM_FIELD_STAGE_LOOKUP;     
            stage_count++;
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */

    if (BCM_FIELD_QSET_TEST(*qset_p, bcmFieldQualifyStageExternal)) {
        *stage  = _BCM_FIELD_STAGE_EXTERNAL;
        stage_count++;
    }

    if (stage_count == 0) {
        /* Default to ingress. */
        *stage = _BCM_FIELD_STAGE_INGRESS;
        stage_count++;
    }

    if (stage_count > 1) {
        FP_ERR(("FP(unit %d) Error: More than one pipeline stage was specified.\n", unit));
        return (BCM_E_PARAM);
    }

    return (BCM_E_NONE);
}


/*
 * Function:
 *     _bcm_field_data_qualifier_free
 *
 * Purpose:
 *     Free data qualifier descriptor structure. 
 *
 * Parameters:
 *     unit       - (IN) BCM device number. 
 *     qual       - (OUT)Qualifier strusture. 
 * 
 * Returns:
 *     BCM_E_XXX 
 */
int
_bcm_field_data_qualifier_free(int unit, _field_data_qualifier_t *qual)
{
    /* Input parameters check. */
    if (NULL == qual) {
        return (BCM_E_PARAM);
    }

    /* Free data offset structure. */
    if (NULL != qual->spec) {
        sal_free(qual->spec);
    }

    /* Free data qualifier structure. */
    sal_free(qual);

    return (BCM_E_NONE);
}


/*
 * Function:
 *     _field_data_qualifier_bmap_alloc
 *
 * Purpose:
 *     Allocate hw resources for data qualifier installation
 * Parameters:
 * Parameters:
 *     unit       - (IN) BCM device number. 
 *     stage_fc   - (IN) Stage field control.
 *     f_dq       - (IN) Field data qualifier descriptor.
 *     idx_low    - (IN) Lower boundary. 
 *     idx_hi     - (IN) Upper boundary.
 * 
 * Returns:
 *     BCM_E_XXX 
 */

STATIC int
_field_data_qualifier_bmap_alloc(int unit,
                               _field_stage_t *stage_fc,
                               _field_data_qualifier_t *f_dq,
                               uint8 idx_low, uint8 idx_hi)
{
    int idx;                 /* Data qualifier word iterator. */
    int elem_count;          /* Number of elements allocated.    */
    uint32   *usage_bmap;    /* Offset usage bitmap.          */


    /* Input parameters check. */
    if ((NULL == f_dq) || (NULL == stage_fc) ||
        (idx_low > 31) || (idx_hi > 31)) {
        return (BCM_E_PARAM);
    }

    elem_count = 0;
    usage_bmap = &stage_fc->data_ctrl->usage_bmap;
    for (idx = idx_low; idx <= idx_hi; idx++) {
        if (0 == ((*usage_bmap) & (1 << idx))) {
            elem_count++;
        }
    }

    if (elem_count >= f_dq->elem_count) {
#if defined(BCM_ENDURO_SUPPORT)   
        if(SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit)) {
            if (idx_hi <= _FP_DATA_DATA0_WORD_MAX) {
                if ((1 == f_dq->elem_count) &&
                    (1 == ((*usage_bmap) & 0xF))) {
                    /* UDF1_31_0 already used. Add UDF1_95_64 */
                    f_dq->hw_bmap |= (1 << 2);
                    (*usage_bmap) |= (1 << 2);
                    return (BCM_E_NONE);
                } else if ((2 == f_dq->elem_count) &&
                           (0 == ((*usage_bmap) & 0xF))) {
                    /* Use both UDF1_31_0 and UDF1_95_64 */
                    f_dq->hw_bmap |= ((1 << 2)|(1 << 0));
                    (*usage_bmap) |= ((1 << 2)|(1 << 0));
                    return (BCM_E_NONE);
                }
            }
        }
#endif /* BCM_ENDURO_SUPPORT */
        elem_count = f_dq->elem_count;
        for (idx = idx_low; ((idx <= idx_hi) && elem_count); idx++) {
            if (0 == ((*usage_bmap) & (1 << idx))) {
                f_dq->hw_bmap |= (1 << idx); 
                (*usage_bmap) |= (1 << idx); 
                elem_count--;
            }
        }
        return (BCM_E_NONE);
    }
    return (BCM_E_RESOURCE);
}

/*
 * Function:
 *     _field_data_qualifier_hw_alloc
 *
 * Purpose:
 *     Allocate hw resources for data qualifier installation
 *
 * Parameters:
 *     unit       - (IN) BCM device number. 
 *     stage_fc   - (IN) Stage field control.
 *     f_dq       - (IN) Field data qualifier descriptor.
 * Returns:
 *     BCM_E_XXX 
 */

STATIC int
_field_data_qualifier_hw_alloc(int unit,
                               _field_stage_t *stage_fc,
                               _field_data_qualifier_t *f_dq)
{
    int rv;               /* Operation return status.        */

    /* Input parameters check. */
    if ((NULL == f_dq) || (NULL == stage_fc)) {
        return (BCM_E_PARAM);
    }

    /* First try to allocate with single udf */ 
    rv = _field_data_qualifier_bmap_alloc
        (unit, stage_fc, f_dq, 0, stage_fc->data_ctrl->num_elems - 1);

    if (BCM_SUCCESS(rv)) {
        return (BCM_E_NONE);
    }
    rv = _field_data_qualifier_bmap_alloc
        (unit, stage_fc, f_dq, stage_fc->data_ctrl->num_elems,
         stage_fc->data_ctrl->num_elems * 2 - 1);

    if (BCM_SUCCESS(rv)) {
        return (BCM_E_NONE);
    }

    /* Need 2 udfs to insert the qualifier. */
    rv  = _field_data_qualifier_bmap_alloc
        (unit, stage_fc, f_dq, 0, stage_fc->data_ctrl->num_elems * 2 - 1);

    return (rv);
} 

/*
 * Function:
 *     _bcm_field_data_qualifier_alloc
 *
 * Purpose:
 *     Allocate data qualifier descriptor structure. 
 *
 * Parameters:
 *     unit       - (IN) BCM device number. 
 *     qual       - (OUT)Qualifier strusture. 
 * 
 * Returns:
 *     BCM_E_XXX 
 */

int
_bcm_field_data_qualifier_alloc(int unit, _field_data_qualifier_t **qual)
{
    int mem_sz;                  /* Allocated memory size.  */
    _field_data_qualifier_p f_dq;/* Data qualifier pointer. */

    /* Input parameters check. */
    if (NULL == qual) {
        return (BCM_E_PARAM);
    }

    /* Allocate field data qualifier structure. */
    mem_sz = sizeof(_field_data_qualifier_t);
    f_dq = sal_alloc(mem_sz, "Data qualifier");
    if (NULL == f_dq) {
        return (BCM_E_MEMORY);
    }
    sal_memset(f_dq, 0, mem_sz);

    /* Allocate offsets spec required for qualifier. */
    mem_sz = sizeof(bcm_field_udf_spec_t);
    f_dq->spec = sal_alloc(mem_sz, "Data spec");
    if (NULL == f_dq->spec) {
        sal_free(f_dq);
        return (BCM_E_MEMORY);
    }
    sal_memset(f_dq->spec->offset, 0xff, sizeof(f_dq->spec->offset));
    *qual = f_dq;

    return (BCM_E_NONE);
}


/*
 * Function:
 *     _field_stage_data_ctrl_init
 *
 * Purpose:
 *     Allocate and initialize data qualifiers control structure. 
 *
 * Parameters:
 *     unit     - (IN)     BCM unit
 *     stage_fc - (IN/OUT) Stage to be initialize.
 * Returns:
 *     BCM_E_XXX 
 */
STATIC int
_field_stage_data_ctrl_init(int unit, _field_stage_t *stage_fc)
{
    int mem_sz; 
    _field_data_control_t *data_ctrl = NULL;

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    /* Allocate data control structure. */
    mem_sz = sizeof(_field_data_control_t);
    _FP_XGS3_ALLOC(data_ctrl, mem_sz, 
                   "Data qualification control");
    if (NULL == data_ctrl) {
        return (BCM_E_MEMORY);
    }

#if defined(BCM_TRIUMPH2_SUPPORT)
    if (SOC_MEM_IS_VALID(unit, FP_UDF_TCAMm)) {
        mem_sz = sizeof (_field_data_tcam_entry_t) * 
            soc_mem_index_count(unit, FP_UDF_TCAMm);
        _FP_XGS3_ALLOC(data_ctrl->tcam_entry_arr, mem_sz, 
                       "Udf tcam entry array.");
        if (NULL == data_ctrl->tcam_entry_arr) {
            sal_free (data_ctrl); 
            return (BCM_E_MEMORY);
        }
    }
#endif /* BCM_TRIUMPH2_SUPPORT */

    if (SOC_MEM_FIELD_VALID(unit, FP_UDF_OFFSETm, UDF1_OFFSET4f)) {
        data_ctrl->elem_size = 2;
        data_ctrl->num_elems = 8;
    } else {
        data_ctrl->elem_size = 4;
        data_ctrl->num_elems = 4;
    }

    stage_fc->data_ctrl = data_ctrl;
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stage_external_data_ctrl_init
 *
 * Purpose:
 *     Allocate and initialize external data qualifiers control structure. 
 *
 * Parameters:
 *     unit     - (IN)     BCM unit
 *     stage_fc - (IN/OUT) Stage to be initialize.
 * Returns:
 *     BCM_E_XXX 
 */
STATIC int
_field_stage_external_data_ctrl_init(int unit, _field_control_t *fc)
{
    _field_stage_t *stage_ingress, *stage_external, *stage_p;

    stage_external = stage_ingress = NULL;
    stage_p = fc->stages;

    while (stage_p) {
        if (stage_p->stage_id == _BCM_FIELD_STAGE_INGRESS) {
            stage_ingress = stage_p;
        } else if (stage_p->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
            stage_external = stage_p;
        }
        stage_p = stage_p->next;
    }

    if ((stage_ingress == NULL) || (stage_external == NULL)) {
        return (BCM_E_INTERNAL);
    }

    stage_external->data_ctrl = stage_ingress->data_ctrl;
    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_data_qualifier_destroy
 * Purpose:
 *      Destroy a data/offset based qualifier.
 * Parameters:
 *      unit  - (IN) Bcm device number.
 *      qid   - (IN) Data qualifier id.
 *                        
 * Returns:
 *      BCM_E_XXX
 */
STATIC int
_field_data_qualifier_destroy(int unit, int qid) 
{
    _field_data_qualifier_t *f_dq;/* Internal data qualifier descriptor. */
    _field_data_qualifier_t *f_dq_prev;/* Prev data qualifier descriptor.*/
    _field_stage_t  *stage_fc;    /* Stage field control.                */
    int rv;                                     

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc); 
    BCM_IF_ERROR_RETURN(rv);

    f_dq_prev = f_dq = stage_fc->data_ctrl->data_qual; 
    while (NULL != f_dq) {
        if (f_dq->qid == qid) {
            /* Free used offset words bitmap. */
            stage_fc->data_ctrl->usage_bmap &= ~f_dq->hw_bmap;

            /* Remove qualifier from qualifiers linked list. */
            if (f_dq == f_dq_prev) {
                stage_fc->data_ctrl->data_qual = f_dq->next;
            } else {
                f_dq_prev->next = f_dq->next;
            }
            /* Free qualifieer allocated memory. */
            return _bcm_field_data_qualifier_free(unit, f_dq);
        }
        f_dq_prev = f_dq;
        f_dq = f_dq->next;
    }
    return (BCM_E_NOT_FOUND);
}

/*
 * Function:
 *      _field_data_qualifier_destroy_all
 * Purpose:
 *      Destroy all data/offset  based qualifiers.
 * Parameters:
 *      unit           - (IN) bcm device.
 * Returns:
 *      BCM_E_XXX
 */
STATIC int
_field_data_qualifier_destroy_all(int unit) 
{
    _field_data_qualifier_t *f_dq;/* Internal data qualifier descriptor. */
    _field_stage_t  *stage_fc;    /* Stage field control.                */
    int rv;                       /* Operation return status.            */

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc); 
    BCM_IF_ERROR_RETURN(rv);

    while (NULL != stage_fc->data_ctrl->data_qual) {
        f_dq = stage_fc->data_ctrl->data_qual; 
        BCM_IF_ERROR_RETURN (_field_data_qualifier_destroy(unit, f_dq->qid));
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stage_data_ctrl_deinit
 *
 * Purpose:
 *     De-allocate data qualifiers control structure. 
 *
 * Parameters:
 *     unit     - (IN)     BCM unit
 *     stage_fc - (IN/OUT) Stage to be initialize.
 * Returns:
 *     BCM_E_XXX 
 */
STATIC int
_field_stage_data_ctrl_deinit(int unit, _field_stage_t *stage_fc)
{
    _field_data_control_t *data_ctrl;

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    if (stage_fc->stage_id != _BCM_FIELD_STAGE_INGRESS) {
        return (BCM_E_NONE);
    }                   

    data_ctrl = stage_fc->data_ctrl;
    if (NULL == data_ctrl) {
        return (BCM_E_NONE);
    }

    /* Delete all data qualifiers. */
    _field_data_qualifier_destroy_all(unit) ;

    /* Free control structures. */
    if (NULL != data_ctrl->tcam_entry_arr) {
        sal_free(data_ctrl->tcam_entry_arr);
    }

    if (NULL != data_ctrl) {
        sal_free(data_ctrl);
    }

    stage_fc->data_ctrl  = NULL;
    return (BCM_E_NONE);
}

/*
 * Function:
 *      _bcm_field_data_qualifier_get
 * Purpose:
 *      Get data qualifier by id.
 * Parameters:
 *      unit           - (IN) bcm device.
 *      stage_fc       - (IN) Stage field control.
 *      qid            - (IN) Qualifier id. 
 *      data_qual      - (OUT) Internal data qualifier descriptor:
 *                         
 * Returns:
 *      BCM_E_XXX
 */
int
_bcm_field_data_qualifier_get(int unit, _field_stage_t *stage_fc,  
                              int qid, _field_data_qualifier_t **data_qual)
{
    _field_data_qualifier_p f_dq;  /* Field data qualifier iterator. */

    /* Input parameters check. */
    if((NULL == data_qual) ||  (NULL == stage_fc)){
        return (BCM_E_PARAM);
    } 

    f_dq = stage_fc->data_ctrl->data_qual; 
    while (NULL != f_dq) {
        if (f_dq->qid == qid) {
            *data_qual = f_dq;
            return (BCM_E_NONE);
        }
        f_dq = f_dq->next;
    }
    return (BCM_E_NOT_FOUND);
}


/*
 * Function:
 *      _field_data_qualifier_id_alloc
 * Purpose:
 *      Allocate unused date qualifier id.
 * Parameters:
 *      unit           - (IN) bcm device.
 *      stage_fc       - (IN) Stage field control.
 *      data_qualifier - (IN) API level qualifier descriptor:
 *                         
 * Returns:
 *      BCM_E_XXX
 */
int
_field_data_qualifier_id_alloc(int unit, _field_stage_t *stage_fc,  
                             bcm_field_data_qualifier_t *data_qualifier)
{
    _field_data_qualifier_t *f_dq;    /* Data qualifier descriptor.    */
    static int last_allocated_qid = _FP_ID_BASE;/* last allocated qid. */
    int max_try;                      /* Maximum number of allocation. */
    int qid;                          /* Qualifier id.                 */
    int rv;                           /* Operation return status.      */


    /* Input parameters check. */
    if ((NULL == data_qualifier) || (NULL == stage_fc)) {
        return (BCM_E_PARAM);
    } 

    /* If qualifier id was passed by the caller, 
       verify the range and make sure id is not used. */
    if (data_qualifier->flags & BCM_FIELD_DATA_QUALIFIER_WITH_ID) {
        qid = data_qualifier->qual_id;
        rv = _bcm_field_data_qualifier_get(unit, stage_fc, qid, &f_dq);
        if (BCM_SUCCESS(rv)) {
            /*  Data qual with requested id already exists */

            if (!(data_qualifier->flags & BCM_FIELD_DATA_QUALIFIER_REPLACE)) {
                /* "Replace" flag was not specified => Return error */

                return (BCM_E_EXISTS);
            }

            /* Destroy existing one */

            _field_data_qualifier_destroy(unit, qid);
        }
        return (BCM_E_NONE);
    } 
    max_try = _FP_ID_MAX;
    qid = last_allocated_qid;
    while (max_try--) {
        rv = _bcm_field_data_qualifier_get(unit, stage_fc, qid, &f_dq);
        if (BCM_E_NOT_FOUND == rv) {
            last_allocated_qid =  qid;
            data_qualifier->qual_id = qid;
            return (BCM_E_NONE);
        }
        if (BCM_FAILURE(rv)) {
            return (rv);
        }
        qid++;
    }
    return (BCM_E_RESOURCE);
}


int
_field_data_qualifier_init2(int                        unit,
                            _field_stage_t             *stage_fc,
                            _field_data_qualifier_t    *f_dq
                            )
{
    int add_offset;               /* Additional offset due to l2         */
                                  /* header size is not multiples of 4.  */

    /* Add to stage's data qual list */
    f_dq->next        = stage_fc->data_ctrl->data_qual;
    stage_fc->data_ctrl->data_qual = f_dq;

    /* Verify data qualifier offset base value. */
#if defined(BCM_TRIUMPH2_SUPPORT)
    if (SOC_MEM_IS_VALID(unit, FP_UDF_TCAMm)) {
        if (stage_fc->data_ctrl->elem_size <= 2) { /* no wrap around needed */
            f_dq->byte_offset = f_dq->offset %
                stage_fc->data_ctrl->elem_size;
        } else {
            if (bcmFieldDataOffsetBasePacketStart ==
                f_dq->offset_base) {
                f_dq->byte_offset = (f_dq->offset + 2) % 4;
            } else {
                f_dq->byte_offset = f_dq->offset % 4;
            }
        }
    } else 
#endif /* BCM_TRIUMPH2_SUPPORT */
    {
        switch (f_dq->offset_base) {
          case bcmFieldDataOffsetBaseOuterL3Header:
          case bcmFieldDataOffsetBaseInnerL3Header:
          case bcmFieldDataOffsetBaseOuterL4Header:
          case bcmFieldDataOffsetBaseInnerL4Header:
              add_offset = 2;
              break;
          case bcmFieldDataOffsetBasePacketStart:
              add_offset = 0;
              break;
          case bcmFieldDataOffsetBaseHigigHeader:
          case bcmFieldDataOffsetBaseHigig2Header:
              if (SOC_IS_FB(unit) ||
                  SOC_IS_HB_GW(unit) ||
                  SOC_IS_SC_CQ(unit)) {
                  add_offset = 2;
              } else {
                  add_offset = 0;
              } 
              break;
          default:
              return (BCM_E_PARAM);
        }

        f_dq->byte_offset = (f_dq->offset + add_offset + 2) % 4;
    }

    return (BCM_E_NONE);
}


int
_field_data_qualifier_init(int                        unit,
                           _field_stage_t             *stage_fc,
                           _field_data_qualifier_t    *f_dq,
                           bcm_field_data_qualifier_t *data_qualifier
                           )
{
    f_dq->qid         = data_qualifier->qual_id;
    f_dq->offset_base = data_qualifier->offset_base;
    f_dq->offset      = data_qualifier->offset;
    f_dq->length      = data_qualifier->length;
    f_dq->flags       = data_qualifier->flags & _BCM_FIELD_DATA_QUALIFIER_FLAGS;

    BCM_IF_ERROR_RETURN(_field_data_qualifier_init2(unit, stage_fc, f_dq));

    f_dq->elem_count = (f_dq->length + f_dq->byte_offset +
                        stage_fc->data_ctrl->elem_size - 1
                        )
        / stage_fc->data_ctrl->elem_size;

    return (BCM_E_NONE);
}


STATIC int
_field_data_qualifier_create(int unit,  
                             bcm_field_data_qualifier_t *data_qualifier)
{
    _field_data_qualifier_t *f_dq;/* Internal data qualifier descriptor. */
    _field_stage_t  *stage_fc;    /* Stage field control.                */
    int rv;                       /* Operation return status.            */

    /* Input parameters check. */
    if (NULL == data_qualifier) {
        return (BCM_E_PARAM);
    }

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Allocate data qualifier id. */
    rv = _field_data_qualifier_id_alloc(unit, stage_fc, data_qualifier);
    BCM_IF_ERROR_RETURN(rv);
    
    /* Allocated internal data qualifier descriptor. */
    rv = _bcm_field_data_qualifier_alloc(unit, &f_dq);
    BCM_IF_ERROR_RETURN(rv);

    /* Initialize internal data qualifier record from given one */
    rv = _field_data_qualifier_init(unit, stage_fc, f_dq, data_qualifier);
    if (BCM_FAILURE(rv)) {
        goto error_cleanup;
    }

    /* Allocate words in hw to accommodate data qualifier. */
    rv = _field_data_qualifier_hw_alloc(unit, stage_fc, f_dq);
    if (BCM_FAILURE(rv)) {
        goto error_cleanup;
    }

    return (BCM_E_NONE);

 error_cleanup:
    _field_data_qualifier_destroy(unit, f_dq->qid);
    
    return (rv);
}

/*
 * Function: _field_qualify_data_elem
 *
 * Purpose:
 *
 * Parameters:
 *     unit          - (IN) BCM device number.
 *     eid           - (IN) Entry ID.
 *     f_dq          - (IN) Data qualifier descriptor.
 *     qual_elem_idx - (IN) Data qualifier element index.
 *     data          - (IN) Data bytes for the indicated data qualifier.
 *                Network byte ordered. 
 *     mask     - Mask bytes for the indicated data qualifier.
 *                Network byte ordered.
 * Returns:
 *     BCM_E_XXX   
 */
int
_field_qualify_data_elem(int unit, bcm_field_entry_t eid,
                         _field_data_qualifier_t *f_dq,
                         uint8 qual_elem_idx,
                         uint32 data, uint32 mask)
{
    _field_stage_t           *stage_fc;
    _bcm_field_qual_offset_t *q_offset;
    _bcm_field_qual_offset_t q_offset_temp;
    _field_entry_t           *f_ent = NULL; 
    int                      idx; 
    int                      rv;
    int                      elem_idx = 0;
    int                      qid = 0;

    /* Input parameters check. */
    if (NULL == f_dq) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN
        (_field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc));

    /* Find a proper element to insert the data. */
    for (idx = 0; idx < stage_fc->data_ctrl->num_elems * 2; idx++) {
        if (f_dq->hw_bmap & (1 << idx)) {
            if (elem_idx == qual_elem_idx) {
                break;
            } else {
                elem_idx++;
            }
        }
    }

    /* Get data qualifier id. */
    if (idx >= 0 && idx < stage_fc->data_ctrl->num_elems) {
#if defined(BCM_ENDURO_SUPPORT)
        if(SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit)) {
            if ((0 == idx) && !(f_dq->hw_bmap & (1 << 0x1)) &&
                              !(f_dq->hw_bmap & (1 << 0x3))) {
                /* qid = UDF1_31_0 */
                qid = _bcmFieldQualifyData2;
            } else if((2 == idx) && !(f_dq->hw_bmap & (1 << 0x1)) &&
                                    !(f_dq->hw_bmap & (1 << 0x3))) {
                /* qid = UDF1_95_64 */
                qid = _bcmFieldQualifyData3;
            } else {
                /* qid = UDF1_127_0 */
                qid = _bcmFieldQualifyData0;
            }
        } else 
#endif /* BCM_ENDURO_SUPPORT */
        {
            qid =  _bcmFieldQualifyData0;
        }
    } else if (idx >= stage_fc->data_ctrl->num_elems &&
               idx < stage_fc->data_ctrl->num_elems * 2) {
        qid =  _bcmFieldQualifyData1;
        idx -= stage_fc->data_ctrl->num_elems;
    } else {
        return (BCM_E_INTERNAL);
    }

    /* Get entry qualifier should be installed in. */
    rv = _bcm_field_entry_qual_get(unit, eid, qid, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get entry qualifier offset in tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qid, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

#if defined(BCM_ENDURO_SUPPORT)
    if(SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit)) {
        if ((qid == _bcmFieldQualifyData2) ||
            (qid == _bcmFieldQualifyData3)) {
            /* Don't have to swap if only one chunk used in UDF1 */
            idx = 0;
        } else {
            idx = (stage_fc->data_ctrl->num_elems - 1) - idx;
        }
    } else
#endif /* BCM_ENDURO_SUPPORT */
    {
        idx = (stage_fc->data_ctrl->num_elems - 1) - idx;
    }

    sal_memcpy(&q_offset_temp, q_offset, 
               sizeof(_bcm_field_qual_offset_t));

    q_offset_temp.offset += idx * stage_fc->data_ctrl->elem_size * 8;
    q_offset_temp.width = stage_fc->data_ctrl->elem_size * 8;

    rv = _bcm_field_qual_value_set(unit, &q_offset_temp, f_ent, &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    f_ent->flags |= _FP_ENTRY_DIRTY;
    return (BCM_E_NONE);
}

/*
 * Function: _field_external_qualify_data_elem
 *
 * Purpose:
 *
 * Parameters:
 *     unit          - (IN) BCM device number.
 *     eid           - (IN) Entry ID.
 *     f_dq          - (IN) Data qualifier descriptor.
 *     qual_elem_idx - (IN) Data qualifier element index.
 *     data          - (IN) Data bytes for the indicated data qualifier.
 *                Network byte ordered. 
 *     mask     - Mask bytes for the indicated data qualifier.
 *                Network byte ordered.
 * Returns:
 *     BCM_E_XXX   
 */
int
_field_external_qualify_data_elem(int unit, bcm_field_entry_t eid,
                         _field_data_qualifier_t *f_dq,
                         uint8 qual_elem_idx,
                         uint32 data, uint32 mask)
{
    _field_stage_t           *stage_fc;
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t           *f_ent = NULL; 
    int                      idx; 
    int                      rv;
    int                      elem_idx = 0;
    int                      qid = 0;

    /* Input parameters check. */
    if (NULL == f_dq) {
        return (BCM_E_PARAM);
    }

    FP_VVERB(("FP(unit %d) vverb: eid (%d): qual_elem_idx (%d)"
        "data (%x) mask (%x)\n", unit, eid, qual_elem_idx, data, mask));

    BCM_IF_ERROR_RETURN
        (_field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc));

    /* Find a proper element to insert the data. */
    for (idx = 0; idx < (stage_fc->data_ctrl->num_elems - 2); idx++) {
        if (f_dq->hw_bmap & (1 << idx)) {
            if (elem_idx == qual_elem_idx) {
                break;
            } else {
                elem_idx++;
            }
        }
    }

    /* Get data qualifier id. */
    if ((f_dq->hw_bmap & 0x1) && (idx >= 0 && idx < 2)) {
        qid =  _bcmFieldQualifyData0;
    } else if ((f_dq->hw_bmap & 0x2) && (idx == 1)) {
        qid =  _bcmFieldQualifyData2;
    } else {
        return (BCM_E_INTERNAL);
    }

    /* Get entry qualifier should be installed in. */
    rv = _bcm_field_entry_qual_get(unit, eid, qid, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get entry qualifier offset in tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qid, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    f_ent->flags |= _FP_ENTRY_DIRTY;
    return (BCM_E_NONE);
}


/*
 * Function: _field_qualify_data
 *
 * Purpose:
 *
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     eid      - (IN) Entry ID.
 *     qual_id  - (IN) Data qualifier id.
 *     data     - (IN) Data bytes for the indicated data qualifier.
 *                     Network byte ordered. 
 *     mask     - (IN) Mask bytes for the indicated data qualifier.
 *                     Network byte ordered.
 *     length   - (IN) data/mask length.
 * Returns:
 *     BCM_E_XXX   
 */
int
_field_qualify_data (int unit, bcm_field_entry_t eid, int qual_id,
                     uint8 *data, uint8 *mask, uint16 length)
{
    _field_stage_t          *stage_fc;  /* Stage field control.       */
    _field_data_qualifier_t *f_dq;      /* Data qualifier descriptor. */
    _field_control_t        *fc;        /* Field control structure.   */
    int                     idx;        /* HW bitmap iteration index. */
    int                     byte_offset;/* Byte offset in the word.   */
    int                     qual_elem_idx; /* Qualifier element index.*/
    uint32                  data_elem;  /* Hw info data word.         */
    uint32                  mask_elem;  /* Hw info data mask.         */
    int                     rv;         /* Operation return status.   */
#ifdef BCM_TRIUMPH_SUPPORT
    _field_entry_t          *entry_p = NULL; /* Field entry pointer */
#endif

    /* Input parameters check. */
    for (idx = 0; idx < length; idx++) {
        if ((NULL == data) || (NULL == mask)) {
            return (BCM_E_PARAM);
        }
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc); 
    BCM_IF_ERROR_RETURN(rv);

    /* Get data qualifier info. */
    rv = _bcm_field_data_qualifier_get(unit, stage_fc, qual_id,  &f_dq);
    BCM_IF_ERROR_RETURN(rv);

    /*
     * If provided entry data length is greater than data length used
     * to create qualifier then return error
     */

    if (length > f_dq->length) {
        return (BCM_E_PARAM);
    }

#ifdef BCM_TRIUMPH_SUPPORT
    if (SOC_IS_TRIUMPH(unit) || SOC_IS_TRIUMPH2(unit)) {
        rv = _field_entry_get(unit, eid, _FP_ENTRY_PRIMARY, &entry_p);
        BCM_IF_ERROR_RETURN(rv);
        /* Get entry qualifier should be installed in. */
        if (entry_p->group->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
            if (length > 4) {
                return (BCM_E_PARAM);
            }
        }
    }
#endif

    data_elem = 0;
    mask_elem = 0;
    qual_elem_idx = 0;
    byte_offset = f_dq->byte_offset;
    for (idx = 0; idx < length; idx++) {
        data_elem |= (data[idx] << (8 * (stage_fc->data_ctrl->elem_size - 1 -
                                         byte_offset)));
        mask_elem |= (mask[idx] << (8 * (stage_fc->data_ctrl->elem_size - 1 -
                                         byte_offset)));
        byte_offset++;
        if (byte_offset == stage_fc->data_ctrl->elem_size) {
            /* Install the element data & mask. */
#ifdef BCM_TRIUMPH_SUPPORT
            if ((SOC_IS_TRIUMPH(unit) || SOC_IS_TRIUMPH2(unit)) &&
                (entry_p->group->stage_id == _BCM_FIELD_STAGE_EXTERNAL)) {
                rv = _field_external_qualify_data_elem(unit, eid,
                                                       f_dq, qual_elem_idx,
                                                       data_elem, mask_elem);
            } else 
#endif
            {
                rv = _field_qualify_data_elem(unit, eid, f_dq, qual_elem_idx,
                                              data_elem, mask_elem);
            }
            BCM_IF_ERROR_RETURN(rv);
            qual_elem_idx++;
            byte_offset = 0;
            data_elem = 0;
            mask_elem = 0;
        }
    }

    /* Install last element data & mask. */
    if (mask_elem != 0) {
#ifdef BCM_TRIUMPH_SUPPORT
        if ((SOC_IS_TRIUMPH(unit) || SOC_IS_TRIUMPH2(unit)) &&
            (entry_p->group->stage_id == _BCM_FIELD_STAGE_EXTERNAL)) {
                rv = _field_external_qualify_data_elem(unit, eid, f_dq,
                                                       qual_elem_idx, data_elem,
                                                       mask_elem);
        } else 
#endif
        {
            rv = _field_qualify_data_elem(unit, eid, f_dq, qual_elem_idx,
                                          data_elem, mask_elem);
        }
    }
    return (rv);
}

/*
 * Function:
 *     _field_selcode_assign
 *
 * Purpose:
 *     Calculate the FPFx select codes from a qualifier set and group mode.
 *
 * Parameters:
 *     unit           - (IN) BCM device number. 
 *     qset           - (IN) Client qualifier set.
 *     selcode_clear  - (IN) Clear the selcodes
 *     fg             - (IN/OUT) Group info structure.
 *
 * Returns:
 *     BCM_E_PARAM    - mode unknown
 *     BCM_E_RESOURCE - No select code will satisfy qualifier set
 *     BCM_E_NONE     - Success
 *
 * Notes:
 *     Calling function is responsible for ensuring appropriate slices
 *     are available.
 *     selcode_clear will be 0 (don't clear) when this function is called 
 *         from bcm_field_group_set
 */
STATIC int
_field_selcode_assign(int unit, bcm_field_qset_t qset, int selcode_clear, 
                      _field_group_t *fg)
{
    _field_stage_t      *stage_fc;  /* Stage field control structure. */
    _field_control_t    *fc;        /* Field control structure.       */ 
    int                 idx;        /* Generic iteration index.       */

    /* Input parameters check. */
    if (NULL == fg) {
        return (BCM_E_PARAM);
    }

    /* Get field control structure for this device. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Get stage FP control info. */
    BCM_IF_ERROR_RETURN
        (_field_stage_control_get(unit, fg->stage_id, &stage_fc));

    /* 
     * Remove the FIXED qualifiers, for fp_selcode_get
     *     as they are always available 
     */

    qset = _field_qset_diff(qset, stage_fc->_field_sel_fixed[0]);

    /* 
     * Clear the group's slice Qsets. 
     *   Selcodes need not be cleared if this function is called from group_set
     */
    for (idx = 0; idx < _FP_MAX_ENTRY_WIDTH; idx++) {
        if (selcode_clear) {
            _FIELD_SELCODE_CLEAR(fg->sel_codes[idx]);
        }
    }

    /* Get select codes based on group flags. */
    BCM_IF_ERROR_RETURN (fc->functions.fp_selcode_get(unit, stage_fc, 
                                                      &qset, fg));
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_counter_collect_deinit
 * Purpose:
 *     Denitialize software field counters. 
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     stage_fc     - (IN/OUT) Stage field control structure.
 *
 * Returns:
 *     BCM_E_XXX
 * NOTE:
 *    FC must be locked & callback deregistred before calling this 
 *    function..  
 */
STATIC int
_field_counter_collect_deinit(int unit, _field_stage_t *stage_fc)
{
    _field_control_t *fc;

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    /* Field control get. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    if (NULL != fc->fc_lock) { 
        FP_LOCK(fc);
    }


    if (NULL !=  stage_fc->_field_x32_counters) {
        sal_free(stage_fc->_field_x32_counters);
        stage_fc->_field_x32_counters = NULL;
    }

#if defined(BCM_EASYRIDER_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT)
    if (NULL !=  stage_fc->_field_ext_counters)  {
        sal_free(stage_fc->_field_ext_counters);
        stage_fc->_field_ext_counters = NULL;
    }
#endif /* BCM_EASYRIDER_SUPPORT || BCM_EASYRIDER_SUPPORT */


#if defined(BCM_BRADLEY_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (NULL !=  stage_fc->_field_x64_counters) {
        sal_free(stage_fc->_field_x64_counters);
        stage_fc->_field_x64_counters = NULL;
    }

    if (NULL !=  stage_fc->_field_y64_counters) {
        sal_free(stage_fc->_field_y64_counters);
        stage_fc->_field_y64_counters = NULL;
    }
#endif /* BCM_BRADLEY_SUPPORT || BCM_TRX_SUPPORT */

#if defined(BCM_SCORPION_SUPPORT)
    if (NULL !=  stage_fc->_field_y32_counters)  {
        sal_free(stage_fc->_field_y32_counters);
        stage_fc->_field_y32_counters = NULL;
    }
#endif /* BCM_SCORPION_SUPPORT */

    if (NULL !=  stage_fc->_field_memacc_counters)  {
        sal_free(stage_fc->_field_memacc_counters);
        stage_fc->_field_memacc_counters = NULL;
    }

    if (NULL != fc->fc_lock) { 
        FP_UNLOCK(fc);
    }

    return (BCM_E_NONE);
}    

/*
 * Function:
 *     _field_meters_deinit
 * Purpose:
 *     Deinitialize field slice meters usage bitmap. 
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     stage_fc     - (IN/OUT) Stage field control structure.
 *
 * Returns:
 *     BCM_E_XXX
 *
 * Notes:
 *     The External stage of Triumph shares the meter pool with Ingress.
 *         free only when it is called for Ingress.
 */
STATIC int
_field_meters_deinit (int unit, _field_stage_t *stage_fc)
{
    _field_slice_t   *slice;      /* Slice config structure. */  
    int              slice_idx;   /* Slices iterator.        */

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_NONE);
    }

    /* Make sure slices array is initialized. */
    if (NULL == stage_fc->slices) {
        return (BCM_E_NONE);
    }

    if (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS) {
        int i;
        if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
            return (BCM_E_NONE);
        }
        for (i = 0; i < stage_fc->num_meter_pools; i++) {
            if (stage_fc->meter_pool[i] != NULL) {
                if (stage_fc->meter_pool[i]->meter_bmp.w != NULL) {
                    sal_free(stage_fc->meter_pool[i]->meter_bmp.w);
                }
                sal_free(stage_fc->meter_pool[i]);
                stage_fc->meter_pool[i] = NULL;
            }
        }

        return BCM_E_NONE;
    }

    for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
        slice = stage_fc->slices + slice_idx;
        if (NULL != slice->meter_bmp.w) {
            sal_free (slice->meter_bmp.w);
        }
        slice->meter_bmp.w = NULL;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_counters_deinit
 * Purpose:
 *     Deinitialize field slice counters bitmap. 
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     stage_fc     - (IN/OUT) Stage field control structure.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_counters_deinit(int unit, _field_stage_t *stage_fc)
{
    _field_slice_t   *slice;      /* Slice config structure.   */  
    int              slice_idx;   /* Slices iterator.        */

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_NONE);
    }

    /* Make sure slices array is initialized. */
    if (NULL == stage_fc->slices) {
        return (BCM_E_NONE);
    }

    /* Destroy 64 bit counters. */
    _field_counter_collect_deinit(unit, stage_fc);

    /*
     * There is an 1-1 mapping between rules and counters 
     * for external FP, so no bitmap was allocated.
     *     (Triumph)
     */
    if (_BCM_FIELD_STAGE_EXTERNAL == stage_fc->stage_id) {
        return (BCM_E_NONE);
    }


    /* Denitialize stage slices info. */
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (_BCM_FIELD_STAGE_EGRESS == stage_fc->stage_id) { 
        if (NULL != stage_fc->slices[0].counter_bmp.w) {
            sal_free (stage_fc->slices[0].counter_bmp.w);
        }
        for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
            stage_fc->slices[slice_idx].counter_bmp.w = NULL;
        }
    } else if (_BCM_FIELD_STAGE_LOOKUP == stage_fc->stage_id) {
#if defined(BCM_TRIUMPH2_SUPPORT)
        /* Deallocate flexible stat counters. */
        if (soc_feature(unit, soc_feature_field_vfp_flex_counter)) {
            _bcm_esw_flex_stat_release_handles(unit, _bcmFlexStatTypeFp);
        }
#endif /* BCM_TRIUMPH2_SUPPORT */
    } else  
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    {
        for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
            slice = stage_fc->slices + slice_idx; 
            if (NULL != slice->counter_bmp.w) {
                sal_free (slice->counter_bmp.w);
            }
            slice->counter_bmp.w = NULL;
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stage_delete
 *
 * Purpose:
 *     Deinitialize field stage.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     fc        - (IN/OUT)Field control info for device.
 *     stage_fc  - (IN) Stage control structure.  
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_stage_delete(int unit, _field_control_t *fc, _field_stage_t *stage_fc)
{
    _field_stage_t        *stage_iter;    /* Device stages iterator. */

    /* Input parameters check. */
    if (NULL == fc) {
        return (BCM_E_PARAM);
    }

    if (NULL == stage_fc) {
        return (BCM_E_NONE);
    }

    /* Destroy data qualifiers control structure */
    _field_stage_data_ctrl_deinit(unit, stage_fc);

    /* Destroy qualifier tables and qsets */
    _field_stage_fpf_destroy(unit, stage_fc);

    /* Free stage slices info. */
    if (NULL != stage_fc->slices) {

        /* Deallocate counters usage bitmap. */
        _field_counters_deinit(unit, stage_fc);

        /* Deallocate meters usage bitmap. */
        _field_meters_deinit(unit, stage_fc);

        /* Deallocate the entry pointers */
        _bcm_field_stage_entries_free(unit, stage_fc);

        /* Deallocate the priority management structures */
        _bcm_field_prio_mgmt_deinit(unit, stage_fc);

        sal_free(stage_fc->slices);
        stage_fc->slices = NULL;
    }

    /* destroy all ranges */
    while (stage_fc->ranges != NULL) {
        bcm_esw_field_range_destroy(unit, stage_fc->ranges->rid);
    }

    /* Destroy redirect action profile. */
    soc_profile_mem_destroy(unit, &stage_fc->redirect_profile);

    /* Destroy action profile */
    soc_profile_mem_destroy(unit, &stage_fc->ext_act_profile);

    /* Remove stage from stages linked list. */
    stage_iter = fc->stages;
    while (NULL != stage_iter) {
        if (stage_iter == stage_fc) {
            fc->stages = stage_fc->next;
            break;
        } else if (stage_iter->next == stage_fc) {
            stage_iter->next = stage_fc->next;
            break;
        }
        stage_iter = stage_iter->next; 
    }

    /* Free stage info. */
    sal_free(stage_fc);

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stages_destroy
 *
 * Purpose:
 *     Deinitialize field stages within the field control struct.
 *
 * Parameters:
 *     unit - (IN) BCM device number.
 *     fc -   (IN/OUT)Field control info for device.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_stages_destroy(int unit, _field_control_t *fc)
{
    _field_stage_t *stage_fc; /* Stage field control structure. */

    /* Input parameters check. */
    if (fc == NULL) {
        return (BCM_E_PARAM);
    }

    if (NULL != fc->fc_lock) { 
        FP_LOCK(fc);
    }

    /* Free stages & slices structures. */ 
    while (NULL != fc->stages) {
        stage_fc = fc->stages;

        /* Free stage resources & stage itself. */
        _field_stage_delete(unit, fc, stage_fc);
    }

    if (NULL != fc->fc_lock) { 
        FP_UNLOCK(fc);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_qset_union
 *
 * Purpose:
 *     make a union of two qsets
 *
 * Parameters:
 *     qset1      - source 1
 *     qset2      - source 2
 *     qset_union - (OUT) result of union operation
 *
 * Returns:
 *     BCM_E_NONE - Success
 */
int
_field_qset_union(const bcm_field_qset_t *qset1,
                  const bcm_field_qset_t *qset2,
                  bcm_field_qset_t *qset_union)
{
    int                    idx;

    if (NULL == qset_union) {
        return (BCM_E_PARAM);
    }


    /* Perform the union of the qualifier bitmap. */
    for (idx = 0; idx < _SHR_BITDCLSIZE(BCM_FIELD_QUALIFY_MAX); idx++) {
        qset_union->w[idx] = qset1->w[idx] | qset2->w[idx];
    }

    /* Perform the union of the qualifier udfs. */
    for (idx = 0; idx < _SHR_BITDCLSIZE(BCM_FIELD_USER_NUM_UDFS); idx++) {
        qset_union->udf_map[idx] = qset1->udf_map[idx] | qset2->udf_map[idx];
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_qset_is_subset
 * Purpose:
 *     Determine if qset one is a subset of qset two.
 * Parameters:
 *     qset_1
 *     qset_2
 * Returns:
 *     TRUE - if 'qset_1' is a subset of 'qset_2'
 *     FALSE - if 'qset_1' is NOT a subset of 'qset_2'
 */
int
_field_qset_is_subset(const bcm_field_qset_t *qset_1,
                      const bcm_field_qset_t *qset_2)
{
    int                 idx;

    for (idx = 0; idx < _SHR_BITDCLSIZE(BCM_FIELD_QUALIFY_MAX); idx++) {
        if ((qset_1->w[idx] | qset_2->w[idx]) & ~qset_2->w[idx]) {
            return (FALSE);
        }
    }
    return (TRUE);
}

/*
 * Function:
 *     _field_qset_diff
 * Purpose:
 *     Calculate the result of subtracting qset_2 from qset_1
 * Parameters:
 *     qset_1 - First parameter
 *     qset_2 - Second parameter
 * Returns:
 *     (qset_1 - qset_2)
 */
bcm_field_qset_t
_field_qset_diff(const bcm_field_qset_t qset_1,
                 const bcm_field_qset_t qset_2)
{
    int                 idx;
    bcm_field_qset_t    qset_result;

    BCM_FIELD_QSET_INIT(qset_result);
    for (idx = 0; idx < _SHR_BITDCLSIZE(BCM_FIELD_QUALIFY_MAX); idx++) {
        qset_result.w[idx] = qset_1.w[idx] & ~qset_2.w[idx];
    }
    return qset_result;
}

/*
 * Function:
 *     _field_qset_is_empty
 * Purpose:
 *     Detect empty Qsets
 * Parameters:
 *     qset - Qset to be tested
 * Returns:
 *     1 if qset has no qualifiers
 *     0 if qset has at least one qualifier
 */
int
_field_qset_is_empty(const bcm_field_qset_t qset)
{
    int                 idx;

    for (idx = 0; idx < _SHR_BITDCLSIZE(BCM_FIELD_QUALIFY_MAX); idx++) {
        if (qset.w[idx] != 0) {
            return 0;
        }
    }
    return 1;
}

/*
 * Function:
 *     _bcm_field_qset_test
 * Purpose:
 *     Identify if qualifier is part of the qset.
 * Parameters:
 *     qid    - Qualifier id.
 *     qset   - Qset to be tested
 *     result - Result
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_qset_test(bcm_field_qualify_t qid, bcm_field_qset_t *qset,
                             uint8 *result)
{
    bcm_field_qset_t  test_qset;

    /* Input parameters check. */
    if ((NULL == qset) || (NULL == result)) {
        return (BCM_E_PARAM);
    }

    BCM_FIELD_QSET_INIT(test_qset);
    BCM_FIELD_QSET_ADD(test_qset, qid); 

    *result = (_field_qset_is_subset(&test_qset, qset)) ? TRUE : FALSE;
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_setup_post_ethertype_udf
 * Purpose:
 *     Specify and create a virtual UDF for the four bytes
 *     that immediately follow the EtherType.
 * Parameters:
 *     unit   - BCM device number
 *     udf_id - Pointer to returned udf_id
 * Returns:
 *     BCM_E_NONE - Virtual UDF created successfully
 *     BCM_E_xxx
 */
int
_bcm_field_setup_post_ethertype_udf(int unit, bcm_field_udf_t *udf_id)
{
    _field_control_t     *fc;
    bcm_field_udf_spec_t *udf_spec;
    uint32               pkt_flags;
    uint32              l2f, vf, ipf, word_offset;
    int                 rv;

    uint32 l2_flag[] = {BCM_FIELD_USER_L2_ETHERNET2,
                        BCM_FIELD_USER_L2_SNAP,
                        BCM_FIELD_USER_L2_LLC};
    uint32 vlan_flag[] = {BCM_FIELD_USER_VLAN_NOTAG,
                          BCM_FIELD_USER_VLAN_ONETAG,
                          BCM_FIELD_USER_VLAN_TWOTAG};
    uint32 ip_flag[] = {BCM_FIELD_USER_IP4_HDR_ONLY,
                        BCM_FIELD_USER_IP6_HDR_ONLY,
                        BCM_FIELD_USER_IP4_OVER_IP4,
                        BCM_FIELD_USER_IP6_OVER_IP4,
                        BCM_FIELD_USER_IP_NOTUSED};

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    udf_spec = sal_alloc(sizeof(bcm_field_udf_spec_t), "UDF spec");
    if (NULL == udf_spec) {
        return (BCM_E_MEMORY);
    }
    sal_memset(udf_spec, 0, sizeof(bcm_field_udf_spec_t));
    /* 
     * Construct a user-defined filter (UDF). 
     *
     * We are looking to examine the first four bytes following the 
     * EtherType field. For an untagged frame, these would be the 
     * 15th-18th bytes of the frame; for a one-VLAN-tagged frame, 
     * the 19th-22nd bytes; a double-VLAN-tagged frame the 23rd-26th. 
     * These byte offsets correspond to the FP word offset selects 4, 
     * 5 and 6 respectively. 
     * The L3 packet format options do not affect the location of
     * these byte fields within the frame. As such, the 
     * BCM_FIELD_USER_OPTION_ADJUST flag is never set.
     *
     * We must explicitly define the various word_offset positions
     * for every applicable type of packet format recognized by the
     * Field Processor. Loop through all applicable combinations of 
     * pkt_flags, specifying the resultant word_offset for each.
     */
    
    for (l2f = 0; l2f < sizeof(l2_flag) / sizeof(uint32); l2f++) {
        for (vf = 0; vf < sizeof(vlan_flag) / sizeof(uint32); vf++) {
            for (ipf = 0; ipf < sizeof(ip_flag) / sizeof(uint32); ipf++) {
                pkt_flags = l2_flag[l2f] | vlan_flag[vf] | ip_flag[ipf];
                switch (vlan_flag[vf]) {
                case BCM_FIELD_USER_VLAN_ONETAG:
                    word_offset = 5;
                    break;
                case BCM_FIELD_USER_VLAN_TWOTAG:
                    word_offset = 6;
                    break;
                default:
                    word_offset = 4;
                    break;
                };
                fc->functions.fp_udf_spec_set(unit, udf_spec, pkt_flags,
                                              word_offset);
            }
        }
    }
    
    rv = bcm_esw_field_udf_create(unit, udf_spec, udf_id);

    sal_free(udf_spec);
    return (rv);
}

/*
 * Function: _bcm_esw_field_group_mode_get
 *
 * Purpose:
 *     Return the mode of a Group ID. This is its single, double or triple-wide
 *     state. Mode specified the number of slices allocated to the group.
 *
 * Parameters:
 *     flags - (IN) Field group flags.
 *     mode  - (OUT) single, double, triple or auto mode.
 *     
 * Returns:
 *     BCM_E_XXX  
 *     
 */
STATIC int
_bcm_esw_field_group_mode_get(uint32 flags, bcm_field_group_mode_t *mode)
{
    /* Input parameters check. */
    if (mode == NULL) {
        return (BCM_E_PARAM);
    }

    if (flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
        *mode = bcmFieldGroupModeTriple;
    } else if (flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
        if (flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            *mode = bcmFieldGroupModeQuad;
        } else {
            *mode = bcmFieldGroupModeDouble;
        }
    } else if (flags & _FP_GROUP_SPAN_SINGLE_SLICE) {
        if (flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            *mode = bcmFieldGroupModeDouble;
        } else {
            *mode = bcmFieldGroupModeSingle;
        }
    }
    return (BCM_E_NONE);
}

#ifdef BROADCOM_DEBUG
/*
 * Function:
 *     _field_qual_name
 * Purpose:
 *     Translate a Qualifier enum value to a text string.
 * Parameters:
 *     Enum value from bcm_field_qualify_e. (ex.bcmFieldQualifyInPorts)
 * Returns:
 *     Text name of indicated qualifier enum value.
 */
STATIC char *
_field_qual_name(bcm_field_qualify_t qid)
{
    /* Text names of the enumerated qualifier IDs. */
    static char *qual_text[bcmFieldQualifyCount] = BCM_FIELD_QUALIFY_STRINGS;

    if (qid < bcmFieldQualifyCount) {
        return qual_text[qid];
    } else if ((int)qid < _bcmFieldQualifyCount) {
        return "_bcmFieldQualifyData";
    }
    return "UnknownQualifier";
}

/*
 * Function:
 *     _field_qual_stage_name
 * Purpose:
 *     Translate a stage qualifier enum value to a text string.
 * Parameters:
 *     Enum value from bcm_field_stage_e. (ex.bcmFieldStageIngressEarly)
 * Returns:
 *     Text name of indicated stage qualifier enum value.
 */
STATIC char *
_field_qual_stage_name(bcm_field_stage_t stage)
{
    /* Text names of the enumerated qualifier stage values. */
    /* All these are prefixed with "bcmFieldStage" */
    static char *stage_text[] = BCM_FIELD_STAGE_STRINGS;

    assert(COUNTOF(stage_text) == bcmFieldStageCount);

    return (stage >= bcmFieldStageCount ? "??" : stage_text[stage]);
}

/*
 * Function:
 *     _field_stage_name
 * Purpose:
 *     Translate group pipeline  stage to a text string.
 * Parameters:
 *     stage_fc stage field control structure. 
 * Returns:
 *     Text name of indicated stage qualifier enum value.
 */
STATIC char *
_field_stage_name(_field_stage_t *stage_fc)
{
    static char *stage_text[] = _BCM_FIELD_STAGE_STRINGS;

    if (stage_fc->stage_id >= COUNTOF(stage_text)) {
        return "??";
    }
    return stage_text[stage_fc->stage_id];
}
 

/*
 * Function:
 *     _field_qual_IpType_name
 * Purpose:
 *     Translate IpType enum value to a text string.
 * Parameters:
 *     Enum value from bcm_field_IpType_e. (ex.bcmFieldIpTypeNonIp)
 * Returns:
 *     Text name of indicated IpType qualifier enum value.
 */
STATIC char *
_field_qual_IpType_name(bcm_field_IpType_t type)
{
    /* Text names of the enumerated qualifier IpType values. */
    /* All these are prefixed with "bcmFieldIpType" */
    static char *iptype_text[bcmFieldIpTypeCount] = BCM_FIELD_IPTYPE_STRINGS;

    assert(COUNTOF(iptype_text) == bcmFieldIpTypeCount);

    return (type >= bcmFieldIpTypeCount ? "??" : iptype_text[type]);
}

/*
 * Function:
 *     _field_action_name
 * Purpose:
 *     Return text name of indicated action enum value.
 */
STATIC char *
_field_action_name(bcm_field_action_t action)
{
    /* Text names of Actions. These are used for debugging output and CLIs.
     * Note that the order needs to match the bcm_field_action_t enum order.
     */
    static char *action_text[] = BCM_FIELD_ACTION_STRINGS;
    assert(COUNTOF(action_text)     == bcmFieldActionCount);

    return (action >= bcmFieldActionCount ? "??" : action_text[action]);
}


/*
 * Function:
 *     _field_group_mode_name
 * Purpose:
 *     Return text name of indicated group mode enum value.
 */
STATIC char *
_field_group_mode_name(uint32 group_flags)
{
    bcm_field_group_mode_t mode;
    static char *mode_text[bcmFieldGroupModeCount] =
                 BCM_FIELD_GROUP_MODE_STRINGS;

    _bcm_esw_field_group_mode_get(group_flags, &mode);

    return (mode >= bcmFieldGroupModeCount ? "??" : mode_text[mode]);
}
#endif /* BROADCOM_DEBUG */

/* Section: Field Initialization */

/*
 * Function: _field_control_free
 *
 * Purpose:
 *    Free field_control structure. 
 *
 * Parameters:
 *     unit - (IN) BCM device number
 *     fc   - (IN) Field control structure.
 *
 * Returns:
 *     BCM_E_XXX  
 */
STATIC int
_field_control_free(int unit, _field_control_t *fc)
{
    _field_control[unit] = NULL;

    if (NULL == fc) {
        return (BCM_E_NONE);
    }

    /* Free protection semaphore. */
    if (NULL != fc->fc_lock) sal_mutex_destroy(fc->fc_lock);

    /* Free software entries lookup hash. */
    if (NULL != fc->entry_hash) sal_free(fc->entry_hash);

    /* Free policers lookup hash. */
    if (NULL != fc->policer_hash) sal_free(fc->policer_hash);

    /* Free counters lookup hash. */
    if (NULL != fc->stat_hash) sal_free(fc->stat_hash);

    /* Free udf configuration. */
    if (NULL != fc->udf) sal_free(fc->udf);

    /* Free module control structure. */
    sal_free(fc);

    return (BCM_E_NONE);
}

int
bcm_esw_field_group_flush(int unit, bcm_field_group_t group)
{
    return BCM_E_UNAVAIL;
}


/*
 * Function:
 *     _field_stages_supported_qset_init
 *
 * Purpose:
 *     Initialize field stages supported qset for each stage
 *
 * Parameters:
 *     unit - (IN) BCM device number.
 *
 * Returns:
 *     BCM_E_NONE   - Success
 *     BCM_E_MEMORY - Allocation failure
 */
STATIC int
_field_stages_supported_qset_init(int unit, _field_control_t *fc)
{
    _field_stage_t   *stage_fc; /* Stage field control structure. */
    bcm_field_qset_t *qset;     /* Operation result.              */
    int idx;                    /* Iteration index.               */

    /* Fill supported qset for each  pipeline stage. */
    stage_fc = fc->stages;
    while (NULL != stage_fc) {
        qset = &stage_fc->_field_supported_qset;
        if ((0 == SOC_IS_EASYRIDER(unit))) {
            for (idx = 0; idx < _bcmFieldQualifyCount; idx++) {
                if (NULL != stage_fc->f_qual_arr[idx]) {
                    BCM_FIELD_QSET_ADD(*qset, (stage_fc->f_qual_arr[idx])->qid);
                }
            }
        } else {
            for (idx = 0; idx < FPF_SZ_MAX; idx++) {
                _field_qset_union(stage_fc->_field_sel_f0 + idx, qset, qset);
                _field_qset_union(stage_fc->_field_sel_f1 + idx, qset, qset);
                _field_qset_union(stage_fc->_field_sel_f2 + idx, qset, qset);
                _field_qset_union(stage_fc->_field_sel_f3 + idx, qset, qset);
                _field_qset_union(stage_fc->_field_sel_f4 + idx, qset, qset);
                _field_qset_union(stage_fc->_field_sel_doublewide + idx, qset, 
                                  qset);
                _field_qset_union(stage_fc->_field_sel_extn + idx, qset, qset);
            }
        }
        _field_qset_union(stage_fc->_field_sel_fixed, qset, qset);
        stage_fc = stage_fc->next; 
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_tcam_info_init
 * Purpose:
 *     Initialize TCAM related information in Field Control
 *
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     stage_fc - (IN) Stage field control structure pointer. 
 *     fc       - (IN/OUT) Field control infoformation for device.
 *
 * Returns:
 *    BCM_E_XXX 
 */
STATIC int
_field_tcam_info_init(int unit, _field_stage_t *stage_fc,  _field_control_t *fc)
{
    soc_mem_t mem = INVALIDm;            /* FP tcam memory id for stage/device. */  

    /* Input parameters check. */
    if ((NULL == fc) || (NULL == stage_fc)) { 
        return (BCM_E_PARAM); 
    }

    if (_BCM_FIELD_STAGE_EXTERNAL == stage_fc->stage_id) {
#ifdef BCM_TRIUMPH_SUPPORT
        if (SOC_IS_TRIUMPH(unit) || SOC_IS_TRIUMPH2(unit)) {
            stage_fc->tcam_slices = 9;
    }
#endif /* BCM_TRIUMPH_SUPPORT */
        return BCM_E_NONE;
    }

    if (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
#ifdef BCM_FIREBOLT_SUPPORT
          if (SOC_IS_FBX(unit)) {
              mem = FP_TCAMm;
          }
#endif /* BCM_FIREBOLT_SUPPORT */

#ifdef BCM_EASYRIDER_SUPPORT
          if (SOC_IS_EASYRIDER(unit)) {
              mem = FP_INTERNALm;
          }
#endif /* BCM_EASYRIDER_SUPPORT */
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    } else if (soc_feature(unit, soc_feature_field_multi_stage)) {
    
        if (_BCM_FIELD_STAGE_LOOKUP  == stage_fc->stage_id) {
            mem = VFP_TCAMm; 
        } else if (_BCM_FIELD_STAGE_EGRESS  == stage_fc->stage_id) { 
            mem = EFP_TCAMm;
        }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT*/
    } else {
        return (BCM_E_UNAVAIL);
    }

    if (INVALIDm == mem) {
        return (BCM_E_UNAVAIL);
    }

    /* Get tcam size. */
    stage_fc->tcam_sz = soc_mem_index_count(unit, mem);

    /* Note fc->tcam_slices only counts internal slices. */
    if (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
        if (soc_feature(unit, soc_feature_field_slices2)) {
            stage_fc->tcam_slices   = 2;
        } else if (soc_feature(unit, soc_feature_field_slices4)) {
            stage_fc->tcam_slices  = 4;
        } else if (soc_feature(unit, soc_feature_field_slices8))  {
            stage_fc->tcam_slices  = 8;
        } else if (soc_feature(unit, soc_feature_field_slices12)) {
            stage_fc->tcam_slices  = 12;
        } else if (soc_feature(unit, soc_feature_field_slices10)) {
            stage_fc->tcam_slices  = 10;
        } else { 
            stage_fc->tcam_slices  = 16;
        }
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    } else if (soc_feature(unit, soc_feature_field_multi_stage)) {
        if (_BCM_FIELD_STAGE_LOOKUP == stage_fc->stage_id) {
            stage_fc->tcam_slices = 4;
        } else if (_BCM_FIELD_STAGE_EGRESS == stage_fc->stage_id) {
            stage_fc->tcam_slices = 4;
        } else {
            return (BCM_E_PARAM);
        }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    } else {
        return (BCM_E_PARAM);
    }


    /*  Check external tcam presence for ingress (default stage) */ 
    /* Only for EasyRider; Triumph taken care of elsewhere */
    fc->tcam_ext_numb = FP_EXT_TCAM_NONE;

    return (BCM_E_NONE);
}


/*
 * Function:
 *     _field_meter_pools_init
 * Purpose:
 *     Initialize field meter pools usage bitmap. 
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     stage_fc     - (IN/OUT) Stage field control structure.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_meter_pools_init(int unit, _field_stage_t *stage_fc)
{
    int              meter_pair_num;   /* Number of meter pairs.    */
    int              pool_idx;         /* Meter pools iterator.     */
    int              size;             /* Allocation size.          */

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    if (0 == (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS)) {
        return (BCM_E_PARAM);
    }

    /* Make sure slices array is initialized. */
    if (NULL == stage_fc->slices) {
        return (BCM_E_INTERNAL);
    }

    /* Set number of meters. */
#if defined(BCM_SCORPION_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
    if (soc_feature(unit, soc_feature_field_meter_pools4)) {
        meter_pair_num = _BCM_FIELD_SC_INGRESS_DOUBLE_WIDE_SLICE_SZ; 
    } else
#endif /* BCM_SCORPION_SUPPORT || BCM_TRIDENT_SUPPORT */
#if defined(BCM_TRIUMPH_SUPPORT)
    if (stage_fc->flags & _FP_STAGE_HALF_SLICE) {
        meter_pair_num = _BCM_FIELD_SLICE_SIZE(stage_fc, 0);
    } else
#endif /* BCM_TRIUMPH_SUPPORT */
    {
        meter_pair_num = _BCM_FIELD_SLICE_SIZE(stage_fc, 0) >> 1;
    }

    size = SHR_BITALLOCSIZE(meter_pair_num);

    /* Get number of meter pools for the device. */
    if (soc_feature(unit, soc_feature_field_meter_pools4)) {
        stage_fc->num_meter_pools = 4;
    } else if (soc_feature(unit, soc_feature_field_meter_pools8)) {
        stage_fc->num_meter_pools = 8;
    } else {
        stage_fc->num_meter_pools = 16;
    }


    for (pool_idx = 0; pool_idx < stage_fc->num_meter_pools; pool_idx++) {
        /* Allocate pool usage bitmap. */
        stage_fc->meter_pool[pool_idx] = 
            sal_alloc(sizeof(_field_meter_pool_t), "fp_meter_pool");
        if (stage_fc->meter_pool[pool_idx] == NULL) {
            _field_meters_deinit (unit, stage_fc);
            return (BCM_E_MEMORY);
        }

        /* Initalize stage meter pool info. */ 
        stage_fc->meter_pool[pool_idx]->slice_id    = -1; /* Pool is not in use. */
        stage_fc->meter_pool[pool_idx]->size        = meter_pair_num;
        stage_fc->meter_pool[pool_idx]->free_meters = meter_pair_num;
        stage_fc->meter_pool[pool_idx]->meter_bmp.w = sal_alloc(size, "fp_meters_map");
        if (stage_fc->meter_pool[pool_idx]->meter_bmp.w == NULL) {
            _field_meters_deinit (unit, stage_fc);
            return (BCM_E_MEMORY);
        }

        /* Reset pool usage bitmap. */
        sal_memset(stage_fc->meter_pool[pool_idx]->meter_bmp.w, 0, size);
    }
    return BCM_E_NONE;
}


/*
 * Function:
 *     _field_meters_init
 * Purpose:
 *     Initialize field slice meters usage bitmap. 
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     fc           - (IN) Field control structure.
 *     stage_fc     - (IN/OUT) Stage field control structure.
 *
 * Returns:
 *     BCM_E_XXX
 * Notes:
 *     Triumph External stage uses the same meter pool as Ingress
 *     It is inited in _field_external_meters_init
 */
STATIC int
_field_meters_init(int unit, _field_stage_t *stage_fc)
{
    int              slice_idx;        /* Slices iterator.          */
    int              size;             /* Allocation size.          */
    _field_slice_t   *fs;              /* Slice config structure.   */  

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    
    /* External config was not processed yet - don't initialize meters.*/
    if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        return (BCM_E_NONE);
    }

    /* Make sure slices array is initialized. */
    if (NULL == stage_fc->slices) {
        return (BCM_E_INTERNAL);
    }

    /* 
     * For devices with global meter pools 
     * Initialize meter pools, skip slice bounded meters . 
     */
    if (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS) {
        return _field_meter_pools_init(unit, stage_fc);
    }

#if defined (BCM_FIREBOLT_SUPPORT)
    if (SOC_IS_FB_FX_HX(unit)) {
        size = SHR_BITALLOCSIZE(_BCM_FIELD_SLICE_SIZE(stage_fc, 0));
    } else 
#endif
    {
        size = SHR_BITALLOCSIZE(_BCM_FIELD_SLICE_SIZE(stage_fc, 0) >> 1);
    }

    /* Iterate over slices & initialize meter infor. */
    for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
        fs = stage_fc->slices + slice_idx;
        /* Allocate meter usage bitmap. */
        fs->meter_bmp.w = sal_alloc(size, "fp_meters_map");
        
        if (NULL == fs->meter_bmp.w) {
            _field_meters_deinit (unit, stage_fc);
            return (BCM_E_MEMORY);
        }

#if defined (BCM_FIREBOLT_SUPPORT)
        if (SOC_IS_FB_FX_HX(unit)) {
            /* Set slice meter count & reset usage bitmap. */
            fs->meters_count = _BCM_FIELD_SLICE_SIZE(stage_fc, 0);
        } else 
#endif
        {
            fs->meters_count = _BCM_FIELD_SLICE_SIZE(stage_fc, 0) >> 1;
        }
        sal_memset(fs->meter_bmp.w, 0, size);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_external_meters_init
 * Purpose:
 *     Initialize field meters for external FP
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     fc           - (IN) Field control structure
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_external_meters_init(int unit, _field_control_t *fc)
{
    int i;
    _field_stage_t *stage_ingress, *stage_external, *stage_p;

    stage_external = stage_ingress = NULL;
    stage_p = fc->stages;

    while (stage_p) {
        if (stage_p->stage_id == _BCM_FIELD_STAGE_INGRESS) {
            stage_ingress = stage_p;
        } else if (stage_p->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
            stage_external = stage_p;
        }
        stage_p = stage_p->next;
    }
    if ((stage_ingress == NULL) || (stage_external == NULL)) {
        return (BCM_E_INTERNAL);
    }

    stage_external->flags |=  _FP_STAGE_GLOBAL_METER_POOLS;
    stage_external->num_meter_pools = stage_ingress->num_meter_pools;
    for (i = 0; i < stage_external->num_meter_pools; i++) {
        if (stage_ingress->meter_pool[i] == NULL) {
            return (BCM_E_INTERNAL);
        }
        stage_external->meter_pool[i] = stage_ingress->meter_pool[i];
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_slice_counters_alloc
 * Purpose:
 *     Allocate counters usage bitmap for a slice. 
 *
 * Parameters:
 *     unit        - (IN) BCM device number.
 *     fs          - (IN/OUT) Slice control structure.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int 
_field_slice_counters_alloc(int unit, _field_slice_t *fs)
{
    int size;            /* Allocation size. */
    /* Input parameters check. */
    if (NULL == fs) {
        return (BCM_E_PARAM);
    }

    size = SHR_BITALLOCSIZE(fs->counters_count);
    fs->counter_bmp.w = sal_alloc(size, "fp_counter_map");
    if (NULL == fs->counter_bmp.w) {
        return (BCM_E_MEMORY);
    }
    sal_memset(fs->counter_bmp.w, 0, size);
    return (BCM_E_NONE);
}

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
/*
 * Function:
 *     _field_slice_counters_share
 * Purpose:
 *     Share counters usage bitmap between slices.
 *
 * Parameters:
 *     unit        - (IN) BCM device number.
 *     stage_fc    - (IN/OUT) Stage field control structure. 
 *     slice_src   - (IN) Slice sharing counters. 
 *     slice_dst   - (IN) Slice receivingshared counters. 
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int 
_field_slice_counters_share(int unit, _field_stage_t *stage_fc, 
                            int slice_src, int slice_dst)
{

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    if (((slice_src < 0) || (slice_src >= stage_fc->tcam_slices)) || 
        ((slice_dst < 0) || (slice_dst >= stage_fc->tcam_slices))) {
        return (BCM_E_PARAM);
    } 

    stage_fc->slices[slice_dst].counter_bmp.w = 
        stage_fc->slices[slice_src].counter_bmp.w;

    return (BCM_E_NONE);
}
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */

/*
 * Function:
 *     _field_counter32_collect_alloc
 * Purpose:
 *     Initialize software field for collection of 32 (or less) bit counters. 
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     mem          - (IN) Counter memory.
 *     descr        - (IN) Counter descriptor. 
 *     ptr          - (OUT) Allocated pointer. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_counter32_collect_alloc(int unit, soc_mem_t mem, char *descr, 
                               _field_counter32_collect_t **ptr)
{
    int mem_size;

    /* Input parameters check. */
    if ((NULL == ptr) || (NULL == descr) || (INVALIDm == mem)) {
        return (BCM_E_PARAM);
    }

    /* Allocate a buffer to track counters. */
    mem_size = (soc_mem_index_count(unit, mem) *  
                                         sizeof(_field_counter32_collect_t));
    *ptr  = sal_alloc(mem_size, descr);
    if (NULL == *ptr) {
        return (BCM_E_MEMORY);
    }
    sal_memset(*ptr, 0, mem_size);
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_counter64_collect_alloc
 * Purpose:
 *     Initialize software field for collection > 32 bit counters. 
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     mem          - (IN) Counter memory.
 *     descr        - (IN) Counter descriptor. 
 *     ptr          - (OUT) Allocated pointer. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_counter64_collect_alloc(int unit, soc_mem_t mem, char *descr, 
                               _field_counter64_collect_t **ptr)
{
    int mem_size;

    /* Input parameters check. */
    if ((NULL == ptr) || (NULL == descr) || (INVALIDm == mem)) {
        return (BCM_E_PARAM);
    }

    /* Allocate a buffer to track counters. */
    mem_size = (soc_mem_index_count(unit, mem) *  
                                         sizeof(_field_counter64_collect_t));
    *ptr  = sal_alloc(mem_size, descr);
    if (NULL == *ptr) {
        return (BCM_E_MEMORY);
    }
    sal_memset(*ptr, 0, mem_size);
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_counter_memacc_alloc
 * Purpose:
 *     Initialize software cached memory access info for field counters 
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     mem          - (IN) Counter memory.
 *     descr        - (IN) Counter descriptor. 
 *     ptr          - (OUT) Allocated pointer. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_counter_memacc_alloc(int unit, soc_memacc_t **memacc_ptr)
{
    int mem_size;

    /* Input parameters check. */
    if (NULL == memacc_ptr) {
        return (BCM_E_PARAM);
    }

    mem_size = _FIELD_COUNTER_MEMACC_NUM * sizeof(soc_memacc_t);
    *memacc_ptr = sal_alloc(mem_size, "FP counter memory access cache");
    if (NULL == *memacc_ptr) {
        return (BCM_E_MEMORY);
    }
    sal_memset(*memacc_ptr, 0, mem_size);
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_counter_collect_init
 * Purpose:
 *     Initialize software field 64bit counters. 
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     fc           - (IN) Field control structure. 
 *     stage_fc     - (IN/OUT) Stage field control structure.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_counter_collect_init(int unit, _field_control_t *fc, 
                            _field_stage_t *stage_fc)
{
    soc_mem_t counter_x_mem;        /* Pipeline 1 counters memory. */
    soc_mem_t counter_y_mem;        /* Pipeline 2 counters memory. */
    soc_memacc_t *memacc_list;      /* Memory access cache list.   */
    int retval = BCM_E_NONE;        /* Operation return status.    */

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    /* 
     * For counter collection in chunks 
     *     Relevant for External Counter Table of Triumph
     */
    stage_fc->counter_collect_table = 0;
    stage_fc->counter_collect_index = 0;
    
    BCM_IF_ERROR_RETURN(_field_counter_mem_get(unit, stage_fc, 
                                               &counter_x_mem, &counter_y_mem));

    /* Check if stage has counters. */
    if (INVALIDm == counter_x_mem) {
        return (BCM_E_NONE);
    }

    /* Allocate space for cached counter memory access info */
    retval = _field_counter_memacc_alloc(unit,
                                   &(stage_fc->_field_memacc_counters));
    if (BCM_FAILURE(retval)) {
        return (retval);
    }
    memacc_list = stage_fc->_field_memacc_counters;

#if defined(BCM_TRX_SUPPORT)
    if (stage_fc->flags & _FP_STAGE_SEPARATE_PACKET_BYTE_COUNTERS) {
        retval = _field_counter32_collect_alloc(unit, counter_x_mem,
                                                "FP pipeline X counters",
                                                &stage_fc->_field_x32_counters);
        if (BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }

        retval = _field_counter64_collect_alloc(unit, counter_x_mem, 
                                                "FP pipeline X byte counters",
                                                &stage_fc->_field_x64_counters);
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }

        retval = soc_memacc_init(unit, counter_x_mem, BYTE_COUNTERf,
                                 &(memacc_list[_FIELD_COUNTER_MEMACC_BYTE]));
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }

        retval = soc_memacc_init(unit, counter_x_mem, PACKET_COUNTERf,
                            &(memacc_list[_FIELD_COUNTER_MEMACC_PACKET]));
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }

#if defined (BCM_SCORPION_SUPPORT)
        if (soc_feature(unit, soc_feature_two_ingress_pipes)) {
            retval = _field_counter32_collect_alloc(unit, counter_y_mem, 
                                                    "FP pipeline Y counters",
                                                    &stage_fc->_field_y32_counters);
            if(BCM_FAILURE(retval)) {
                _field_counter_collect_deinit(unit, stage_fc);
                return (retval);
            }

            retval = _field_counter64_collect_alloc(unit, counter_y_mem, 
                                                    "FP pipeline Y byte counters",
                                                    &stage_fc->_field_y64_counters);
            if(BCM_FAILURE(retval)) {
                _field_counter_collect_deinit(unit, stage_fc);
                return (retval);
            }

            retval = soc_memacc_init(unit, counter_y_mem, BYTE_COUNTERf,
                         &(memacc_list[_FIELD_COUNTER_MEMACC_BYTE_Y]));
            if(BCM_FAILURE(retval)) {
                _field_counter_collect_deinit(unit, stage_fc);
                return (retval);
            }

            retval = soc_memacc_init(unit, counter_y_mem, PACKET_COUNTERf,
                         &(memacc_list[_FIELD_COUNTER_MEMACC_PACKET_Y]));
            if(BCM_FAILURE(retval)) {
                _field_counter_collect_deinit(unit, stage_fc);
                return (retval);
            }

        }
#endif /* BCM_SCORPION_SUPPORT */
    } else 
#endif /* BCM_TRX_SUPPORT */

#if defined(BCM_BRADLEY_SUPPORT) 
    if (soc_feature(unit, soc_feature_two_ingress_pipes)) {
        retval = _field_counter64_collect_alloc(unit, counter_x_mem,
                                                "FP pipeline X byte cntrs",
                                                &stage_fc->_field_x64_counters);
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }

        retval = soc_memacc_init(unit, counter_x_mem, COUNTERf,
                     &(memacc_list[_FIELD_COUNTER_MEMACC_COUNTER]));
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }

        retval = _field_counter64_collect_alloc(unit, counter_y_mem,
                                                "FP pipeline Y byte cntrs",
                                                &stage_fc->_field_y64_counters);
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }

        retval = soc_memacc_init(unit, counter_y_mem, COUNTERf,
                     &(memacc_list[_FIELD_COUNTER_MEMACC_COUNTER_Y]));
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }
    } else 
#endif /* BCM_BRADLEY_SUPPORT */
    {
        retval = _field_counter32_collect_alloc(unit, counter_x_mem, 
                                                "FP pipeline X counters",
                                                &stage_fc->_field_x32_counters);
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }

        retval = soc_memacc_init(unit, counter_x_mem, COUNTERf,
                     &(memacc_list[_FIELD_COUNTER_MEMACC_COUNTER]));
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }
    }

#if defined(BCM_EASYRIDER_SUPPORT)
    if (SOC_IS_EASYRIDER(unit) && (FP_EXT_TCAM_NONE != fc->tcam_ext_numb)) {
        retval = _field_counter32_collect_alloc(unit, counter_y_mem, 
                                                "External FP counters",
                                                &stage_fc->_field_ext_counters);
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }

        retval = soc_memacc_init(unit, counter_y_mem, COUNTERf,
                     &(memacc_list[_FIELD_COUNTER_MEMACC_COUNTER_Y]));
        if(BCM_FAILURE(retval)) {
            _field_counter_collect_deinit(unit, stage_fc);
            return (retval);
        }
    }
#endif /* BCM_EASYRIDER_SUPPORT */
    return (retval);
}

/*
 * Function:
 *     _field_counters_init
 * Purpose:
 *     Initialize field slice counters bitmap. 
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     fc           - (IN) Field control structure. 
 *     stage_fc     - (IN/OUT) Stage field control structure.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_counters_init(int unit, _field_control_t *fc, 
                     _field_stage_t *stage_fc)
{
    _field_slice_t   *fs;                 /* Slice config structure.    */  
    int              slice_idx;           /* Slices iterator.           */
    int              retval;              /* Operation return value.    */
    int              cntr_share = FALSE;  /* Share counter with slice 0 */

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    /* Make sure slices array is initialized. */
    if (NULL == stage_fc->slices) {
        return (BCM_E_INTERNAL);
    }


    /* Allocate software 64 bit counters image. */  
    BCM_IF_ERROR_RETURN(_field_counter_collect_init(unit, fc, stage_fc));

#if defined(BCM_TRIUMPH_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT)
    /*
     * There is an 1-1 mapping between rules and counters 
     * for external FP, so no bitmap needs to be allocated
     *     (Triumph)
     */
    if (_BCM_FIELD_STAGE_EXTERNAL == stage_fc->stage_id) {
        return (BCM_E_NONE);
    }
#endif /* BCM_TRIUMPH_SUPPORT || BCM_TRIUMPH2_SUPPORT */

    /* Allocate counters for each of the tcam slices. */
    for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
        fs = stage_fc->slices + slice_idx;
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
        if (_BCM_FIELD_STAGE_LOOKUP == stage_fc->stage_id) { 
            fs->counters_count = 0;
            continue;
        } else if (_BCM_FIELD_STAGE_EGRESS == stage_fc->stage_id) {
            fs->counters_count = soc_mem_index_count(unit, EFP_COUNTER_TABLEm);
            if (slice_idx) {
                cntr_share = TRUE; 
            } 
        } else 
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
        {
            fs->counters_count = fs->entry_count;
        }

        if (cntr_share) {
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
            /* Share counters with slice zero(Global counter pool). */
            retval = _field_slice_counters_share(unit, stage_fc,
                                                 0, slice_idx);
            if (BCM_FAILURE(retval)) {
                _field_counters_deinit(unit, stage_fc);
                return (retval);
            }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
        } else {
            /* Allocate new set of counters for the slice. */
            retval = _field_slice_counters_alloc(unit, fs);
            if (BCM_FAILURE(retval)) {
                _field_counters_deinit(unit, stage_fc);
                return (retval);
            }
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_entries_init
 * Purpose:
 *     Allocate the memory for entries in all the slices of the stage.
 *     External TCAM (for Triumph) is taken care of in _bcm_tr_field_init.
 *     Entries  will be de-allocated in bcm_esw_field_detach
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     stage_fc     - (IN/OUT) Stage field control structure.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_entries_init(int unit, _field_stage_t *stage_fc)
{
    int              slice_idx;    /* Slices iterator.                      */
    int              tcam_idx;     /* Slice first entry tcam index tracker. */
    int              mem_size;     /* Allocation size.                      */
    int              entry_ratio;  /* Invalid entries ratio.                */
    _field_slice_t   *fs;          /* Slice config structure.               */  


    /* Input parameters check. */
    if (NULL == stage_fc)  {
        return (BCM_E_PARAM);
    }

    /* Triumph external slice handled in _bcm_tr_field_init. */
    if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        return (BCM_E_NONE);
    }

    /* Make sure slices array is initialized. */
    if (NULL == stage_fc->slices) {
        return (BCM_E_INTERNAL);
    }

    entry_ratio = (stage_fc->flags & _FP_STAGE_HALF_SLICE) ? 2 : 1;

    /* Iterate over all stage slices and allocated entries for each slice. */
    for (slice_idx = 0, tcam_idx = 0; 
         slice_idx < stage_fc->tcam_slices; slice_idx++) {

        /* Get slice control structure pointer. */
        fs = stage_fc->slices + slice_idx;

        /* Get number of entries in the slice. */
#if defined(BCM_SCORPION_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
        if ((soc_feature(unit, soc_feature_field_ingress_two_slice_types)) && 
            (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id)) {
             if (SOC_IS_TD_TT(unit)){
                if (slice_idx < _BCM_FIELD_TD_INGRESS_DOUBLE_WIDE_SLICE0) {
                    fs->entry_count =
                        _BCM_FIELD_TD_INGRESS_SINGLE_WIDE_SLICE_SZ;
                } else {
                    fs->entry_count =
                        _BCM_FIELD_TD_INGRESS_DOUBLE_WIDE_SLICE_SZ;
                }
            } else {
                if (slice_idx < _BCM_FIELD_SC_INGRESS_DOUBLE_WIDE_SLICE0) {
                    fs->entry_count =
                        _BCM_FIELD_SC_INGRESS_SINGLE_WIDE_SLICE_SZ;
                } else {
                    fs->entry_count =
                        _BCM_FIELD_SC_INGRESS_DOUBLE_WIDE_SLICE_SZ;
                }
            }
        } else 
#endif /* BCM_SCORPION_SUPPORT || BCM_TRIDENT_SUPPORT */
        fs->entry_count = stage_fc->tcam_sz / (entry_ratio * stage_fc->tcam_slices);
        
        /* Allocate slice entries pointers array. */
        mem_size = fs->entry_count * sizeof (void *);
        _FP_XGS3_ALLOC(fs->entries, mem_size, "array of entry pointers");
        if (fs->entries == NULL) {
            /* Allocation failed free all previously allocated entries. */
            _bcm_field_stage_entries_free(unit, stage_fc);
            return (BCM_E_MEMORY);
        }
        fs->start_tcam_idx = tcam_idx;
        tcam_idx += fs->entry_count * entry_ratio;
        fs->free_count = fs->entry_count;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_slices_init
 * Purpose:
 *     Allocate the memory for slices. 
 *     Initialize slice specific flags, parameters.
 *
 * Parameters:
 *     unit         - (IN) BCM device number.
 *     stage_fc     - (IN/OUT) Stage field control structure.
 *     fc           - (IN/OUT) Field control structure. 
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_slices_init(int unit, _field_stage_t *stage_fc, _field_control_t *fc)
{
    struct _field_slice_s *fs; /* Slice info.                    */
    int             slice_idx; /* Slice iteration index.         */
    int              mem_size; /* Memory allocation buffer size. */

    /* Input parameters check. */
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    /* Allocate slices info. */
    mem_size = stage_fc->tcam_slices * sizeof(struct _field_slice_s);
    fs = sal_alloc(mem_size, "stage slices info");
    if (NULL == fs) {
        return (BCM_E_MEMORY);
    }

    sal_memset(fs, 0, mem_size);
    stage_fc->slices = fs;

    /* Initialize stage slices info. */
    for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
        fs[slice_idx].slice_number = slice_idx;
        fs[slice_idx].stage_id = stage_fc->stage_id;
        fs[slice_idx].next = NULL;
        fs[slice_idx].prev = NULL;
        fs[slice_idx].doublewide_key_select = _FP_SELCODE_DONT_CARE;
        fs[slice_idx].src_class_sel = _FP_SELCODE_DONT_CARE;
        fs[slice_idx].dst_class_sel = _FP_SELCODE_DONT_CARE;
        fs[slice_idx].intf_class_sel = _FP_SELCODE_DONT_CARE;
        fs[slice_idx].loopback_type_sel = _FP_SELCODE_DONT_CARE;
        fs[slice_idx].ingress_entity_sel = _FP_SELCODE_DONT_CARE;
        fs[slice_idx].src_entity_sel = _FP_SELCODE_DONT_CARE;        
        fs[slice_idx].dst_fwd_entity_sel = _FP_SELCODE_DONT_CARE;
        fs[slice_idx].fwd_field_sel = _FP_SELCODE_DONT_CARE;

        /* Set intraslice  capable flag if appropriate. */
#ifdef BCM_HURRICANE_SUPPORT
        if (SOC_IS_HURRICANE(unit)) {
            fs[slice_idx].slice_flags |= _BCM_FIELD_SLICE_INTRASLICE_CAPABLE;
        }
#endif
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
        if (soc_feature(unit, soc_feature_field_multi_stage)) {
            if ((_BCM_FIELD_STAGE_INGRESS != stage_fc->stage_id) && 
                (_BCM_FIELD_STAGE_LOOKUP  != stage_fc->stage_id)) {
                continue;
            }

#if defined(BCM_SCORPION_SUPPORT) || defined (BCM_TRIDENT_SUPPORT)
            /* Skip single wide slices on 5682x devices. */
            if ((soc_feature(unit, soc_feature_field_ingress_two_slice_types)) &&
                (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id)) {
                if (SOC_IS_TD_TT(unit)) {
                    if (_BCM_FIELD_TD_INGRESS_DOUBLE_WIDE_SLICE0 > slice_idx) {
                        fs[slice_idx].slice_flags |= _BCM_FIELD_SLICE_SIZE_SMALL;
                        continue;
                    }
                } else {
                    if (_BCM_FIELD_SC_INGRESS_DOUBLE_WIDE_SLICE0 > slice_idx) {
                        fs[slice_idx].slice_flags |= _BCM_FIELD_SLICE_SIZE_SMALL;
                        continue;
                    }
                }
                fs[slice_idx].slice_flags |= _BCM_FIELD_SLICE_SIZE_LARGE;
            }
#endif /* BCM_SCORPION_SUPPORT || BCM_TRIDENT_SUPPORT */
            fs[slice_idx].slice_flags |= _BCM_FIELD_SLICE_INTRASLICE_CAPABLE;
        }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stage_add
 *
 * Purpose:
 *     Add stage to field processor pipeline.
 *
 * Parameters:
 *     unit - (IN) BCM device number.
 *     fc -   (IN/OUT)Field control info for device.
 *
 * Returns:
 *     BCM_E_NONE   - Success
 *     BCM_E_MEMORY - Allocation failure
 */
STATIC int
_field_stage_add(int unit, _field_control_t *fc, _field_stage_id_t stage_id)
{
    _field_stage_t *stage_fc; /* Stage info.                 */
    int    ret_val;           /* Operation return value.     */
    int    idx;               
    int    map_id; 
#if defined(BCM_TRX_SUPPORT)
    soc_mem_t mem;
    int entry_words;
#endif /* BCM_TRX_SUPPORT */
#if defined(BCM_TRIUMPH_SUPPORT)  
    uint16              dev_id;
    uint8               rev_id;
#endif /* BCM_TRIUMPH_SUPPORT */

    /* Input parameters check. */
    if (NULL == fc) {
        return (BCM_E_PARAM);
    }

    /* Allocate stage structure. */
    stage_fc = sal_alloc(sizeof(_field_stage_t), "FP stage info");
    if (NULL == stage_fc) {
        FP_ERR(("FP(unit %d) Error: Allocation failure for stage info\n", unit));
        return (BCM_E_MEMORY);
    }
    /* Reset allocated buffer. */
    sal_memset(stage_fc, 0, sizeof(_field_stage_t));

    /* Set stage id. */
    stage_fc->stage_id = stage_id;

    /* Set the stage features */
    if ((soc_feature(unit, soc_feature_field_ingress_global_meter_pools)) &&
        (stage_id == _BCM_FIELD_STAGE_INGRESS)) {
        stage_fc->flags |= _FP_STAGE_GLOBAL_METER_POOLS;
    }

#if defined(BCM_TRIUMPH_SUPPORT)  
    if (SOC_IS_VALKYRIE(unit) || SOC_IS_VALKYRIE2(unit)) {
        stage_fc->flags |= _FP_STAGE_HALF_SLICE;
    } else if (SOC_IS_APOLLO(unit) && (_BCM_FIELD_STAGE_LOOKUP != stage_id)) {
        stage_fc->flags |= _FP_STAGE_HALF_SLICE;
    }
    
    /* 56620/56630 devices have full slices on all stages. */
    /* 56538/56534 devices have half slices on ingress and egress */
    soc_cm_get_id(unit, &dev_id, &rev_id);
    if (((BCM56538_DEVICE_ID == dev_id) || (BCM56534_DEVICE_ID == dev_id)) && 
        (_BCM_FIELD_STAGE_LOOKUP != stage_id)) {
        stage_fc->flags |= _FP_STAGE_HALF_SLICE;
    }
    if ((BCM56630_DEVICE_ID == dev_id) || (BCM56620_DEVICE_ID == dev_id)) {
        stage_fc->flags &= ~_FP_STAGE_HALF_SLICE;
    }
#endif /* BCM_TRIUMPH_SUPPORT */

#if defined(BCM_TRX_SUPPORT)
    if ((soc_feature(unit, 
                    soc_feature_field_ing_egr_separate_packet_byte_counters)) &&
        ((stage_id == _BCM_FIELD_STAGE_INGRESS) || 
         (stage_id == _BCM_FIELD_STAGE_EXTERNAL) ||
         (stage_id == _BCM_FIELD_STAGE_EGRESS))) {
        stage_fc->flags |= _FP_STAGE_SEPARATE_PACKET_BYTE_COUNTERS;
    } 
#endif /* BCM_TRX_SUPPORT  */

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) 
    if ((soc_feature(unit, soc_feature_field_egress_global_counters)) &&
        (stage_id == _BCM_FIELD_STAGE_EGRESS)) {
        stage_fc->flags |= _FP_STAGE_GLOBAL_COUNTERS;
    }
    if ((soc_feature(unit, soc_feature_field_vfp_flex_counter)) &&
        (stage_id == _BCM_FIELD_STAGE_LOOKUP)) {
        stage_fc->flags |= _FP_STAGE_GLOBAL_COUNTERS;
    }
    if (SOC_IS_KATANA(unit)) {
        if ((soc_feature(unit, soc_feature_advanced_flex_counter)) &&
            (stage_id == _BCM_FIELD_STAGE_LOOKUP)) {
            stage_fc->flags |= _FP_STAGE_GLOBAL_COUNTERS;
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT  || BCM_TRX_SUPPORT */
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) || \
    defined(BCM_RAPTOR_SUPPORT)
    if ((soc_feature(unit, soc_feature_field_virtual_slice_group) && 
         (_BCM_FIELD_STAGE_INGRESS == stage_id)) ||
        (SOC_IS_TRX(unit) && (_BCM_FIELD_STAGE_EXTERNAL != stage_id)
         && soc_feature(unit, soc_feature_field_virtual_slice_group))) {
        stage_fc->flags |= _FP_STAGE_AUTO_EXPANSION;
    }
#endif /* BCM_FIREBOLT2_SUPPORT  || BCM_TRX_SUPPORT || BCM_RAPTOR_SUPPORT */
    if ((soc_feature(unit, soc_feature_field_slice_enable)) && 
        (_BCM_FIELD_STAGE_EXTERNAL != stage_id)) {
        stage_fc->flags |= _FP_STAGE_SLICE_ENABLE;
    } 
    
    /* Init tcam info for stage. */
    ret_val = _field_tcam_info_init(unit, stage_fc, fc);
    if (BCM_FAILURE(ret_val)) {
        _field_stage_delete(unit, fc, stage_fc);
        return (ret_val);
    }

    /* Initialize slices information. */
    ret_val = _field_slices_init (unit, stage_fc, fc);
    if (BCM_FAILURE(ret_val)) {
        _field_stage_delete(unit, fc, stage_fc);
        return (ret_val);  
    }

    /*
     * Allocate the memory for entries in all the slices
     *     external TCAM (for Triumph) is taken care of in _bcm_tr_field_init.
     * This will be de-allocated in bcm_esw_field_detach
     */
    if (stage_fc->stage_id != _BCM_FIELD_STAGE_EXTERNAL) {
        /* Initialize stage slices . */
        ret_val = _field_entries_init (unit, stage_fc);
        if (BCM_FAILURE(ret_val)) {
            _field_stage_delete(unit, fc, stage_fc);
            return (ret_val);
        }
    }

    /* Initialize meters usage bitmap. */
    ret_val = _field_meters_init (unit, stage_fc);
    if (BCM_FAILURE(ret_val)) {
        _field_stage_delete(unit, fc, stage_fc);
        return (ret_val);  
    }

    /* Initialize counters usage bitmap. */
    ret_val = _field_counters_init(unit, fc, stage_fc);
    if (BCM_FAILURE(ret_val)) {
        _field_stage_delete(unit, fc, stage_fc);
        return (ret_val);  
    }

    /* Redirect action memory profile initialization. */ 
    soc_profile_mem_t_init(&stage_fc->redirect_profile);

    /* Action profile; will be setup in chip-specific init */
    soc_profile_mem_t_init(&stage_fc->ext_act_profile);

    /* Ingress specific initialization. */
    if (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
        
#if defined(BCM_TRX_SUPPORT)
        /* Redirection action profile table initialization. */
        if (SOC_MEM_IS_VALID(unit, IFP_REDIRECTION_PROFILEm)) {
            mem = IFP_REDIRECTION_PROFILEm;
            entry_words = sizeof(ifp_redirection_profile_entry_t) /
                sizeof(uint32);
            ret_val = soc_profile_mem_create(unit, &mem, &entry_words, 1,
                                             &stage_fc->redirect_profile);

            if (BCM_FAILURE(ret_val)) {
                _field_stage_delete(unit, fc, stage_fc);
                return (ret_val);
            }
        }
#endif /* BCM_TRX_SUPPORT */
        stage_fc->range_id = 1;

        /* Initialize stage select codes table. */
        ret_val = _field_stage_data_ctrl_init(unit, stage_fc);
        if (BCM_FAILURE(ret_val)) {
            _field_stage_delete(unit, fc, stage_fc);
            return (ret_val);  
        }
    }

    /* Initialize stage select codes table. */
    ret_val = _field_stage_fpf_init(unit, stage_fc);
    if (BCM_FAILURE(ret_val)) {
        _field_stage_delete(unit, fc, stage_fc);
        return (ret_val);  
    }

    /*
     * Initialize the FP_SLICE_MAP
     *     physical_slice and virtual_group are H/W initial values
     * Although initialized for all stages, valid only on Raptor (1 stage)
     *     , FB-2 Ingress stage, Triumph 
     */
    for (map_id = 0; map_id < _FP_VMAP_CNT; map_id++) {
        for (idx = 0; idx < _FP_VMAP_SIZE; idx++) {
            stage_fc->vmap[map_id][idx].valid = FALSE;
            stage_fc->vmap[map_id][idx].vmap_key = idx;
            stage_fc->vmap[map_id][idx].virtual_group = idx;
            stage_fc->vmap[map_id][idx].flags = 0;
        }
    }

    FP_LOCK(fc);
    /* Add stage to field control structure. */
    stage_fc->next = fc->stages;
    fc->stages = stage_fc;
    FP_UNLOCK(fc);    

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_stages_init
 *
 * Purpose:
 *     Initialize field stages array within the field control struct.
 *
 * Parameters:
 *     unit - (IN) BCM device number.
 *     fc -   (IN/OUT)Field control info for device.
 *
 * Returns:
 *     BCM_E_NONE   - Success
 *     BCM_E_MEMORY - Allocation failure
 *
 * Notes:
 *     It is important that _BCM_FIELD_STAGE_INGRESS be inited before
 *         _BCM_FIELD_STAGE_EXTERNAL
 */
STATIC int
_field_stages_init(int unit, _field_control_t *fc)
{
    int            ret_val;    /* Operation return value.     */
   

    /* Input parameters check. */
    if (fc == NULL) {
        return (BCM_E_PARAM);
    }

    /* Based on unit type add pipeline stages to field control. */

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if ((soc_feature(unit, soc_feature_field_multi_stage)) && 
        (SOC_SWITCH_BYPASS_MODE_L3_ONLY != SOC_SWITCH_BYPASS_MODE(unit))) {

        ret_val = _field_stage_add(unit, fc, _BCM_FIELD_STAGE_LOOKUP);
        if (BCM_FAILURE(ret_val)) {
            _field_stages_destroy(unit, fc);
            return (ret_val);
        }

        ret_val = _field_stage_add(unit, fc, _BCM_FIELD_STAGE_EGRESS);
        if (BCM_FAILURE(ret_val)) {
            _field_stages_destroy(unit, fc);
            return (ret_val);
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */

    ret_val = _field_stage_add(unit, fc, _BCM_FIELD_STAGE_INGRESS);
    if (BCM_FAILURE(ret_val)) {
        _field_stages_destroy(unit, fc);
        return (ret_val);
    }

    /* Add the External TCAM (stage) */
    if ((soc_feature(unit, soc_feature_esm_support)) &&
        (fc->flags & _FP_EXTERNAL_PRESENT)) {
        ret_val = _field_stage_add(unit, fc, _BCM_FIELD_STAGE_EXTERNAL);
        if (BCM_FAILURE(ret_val)) {
            _field_stages_destroy(unit, fc);
            return (ret_val);
        }

        ret_val = _field_external_meters_init(unit, fc);
        if (BCM_FAILURE(ret_val)) {
            _field_stages_destroy(unit, fc);
            return (ret_val);
        }

        ret_val = _field_stage_external_data_ctrl_init(unit, fc);
        if (BCM_FAILURE(ret_val)) {
            _field_stages_destroy(unit, fc);
            return (ret_val);
        }
    }
    return (ret_val);

}
/*
 * Function: _field_min_virtual_priorty_group_get
 *
 * Purpose:
 *     Service routine used to update virtual priority map.
 *     Function returns a minimum priority group, which 
 *     might be assigned a virtual priority passed to the function.
 * Parameters:
 *     unit           - (IN) BCM device number. 
 *     vmap           - (IN) Virutal map array.
 *     vmap_size      - (IN) Map size.
 *     unused_groups  - (OUT) Unused virtual groups.
 *     unused_slices  - (OUT) Unused physical slices.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_min_virtual_priorty_group_get(int unit, _field_virtual_map_t *vmap,
                                     int vmap_size, int *virtual_priority, 
                                     int *candidate)
{
    int idx;                     /* Virtual map iteration index.  */
    int prio_max;                /* Max limit on group priority.  */
    int min_group;               /* Minimum priority group index. */
    int even_boundary_constraint;/*  even boundary constraint     */
    int incr_priority = FALSE;   /* Increment priority to meet    */

    /* Input parameters check. */
    if ((NULL == vmap) || (NULL ==  candidate) || (NULL == virtual_priority)) {
        return (BCM_E_PARAM);
    }

    /* Initialize max limit for group priority to ANY (unlimited). */
    prio_max  = 0x7fffffff; /* Unlimited priority.*/
    min_group = -1;         /* No candidates.    */

    /* FB2 double wide group must reside in even virtual priority. */
    even_boundary_constraint = (SOC_IS_FIREBOLT2(unit)) ? TRUE : FALSE;

    /* Fill new virtual map. */
    for (idx = 0; idx <  vmap_size; idx++) {

        /* Skip unused virtual priorities. */
        if (vmap[idx].valid == FALSE) {
            continue;
        }

        /* Skip groups not meeting even_boundary_constraint */
        if ((even_boundary_constraint) &&
            (vmap[idx].flags & _FP_GROUP_SPAN_DOUBLE_SLICE)  &&
            (0 != ((*virtual_priority) % 2))) {
            if (prio_max > vmap[idx].priority) {
                prio_max = vmap[idx].priority;
            }
            if (-1 == min_group)  {
                min_group = idx;
                /* Priority increment is required.*/
                incr_priority = TRUE;
            }
            /* Double wide group -> no point to check next map. */ 
            idx ++;
            continue;
        }

        /*
         *  Make sure double wide group with 
         *  lower priority was not skipped because of even_boundary_constraint.
         */
        if (prio_max >= vmap[idx].priority) {
            min_group = idx;
            incr_priority = FALSE;
        }
        break;
    }

    if (incr_priority) {
        /*
         *  Originally, a candidate was skipped because of 
         *  even boundary constraint violation (virtual_priority is odd).
         *  lets use next priority. 
         */    
        (*virtual_priority)++;
    }

    *candidate = min_group;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_slice_clear
 *
 * Purpose:
 *     Reset the fields in a slice. Note that the entries list must be
 *     empty before calling this. Also, this does NOT deallocate the memory for
 *     the slice itself. Normally, this is used when a group no longer needs
 *     ownership of a slice so the slice gets returned to the pool of available
 *     slices.
 *
 * Paramters:
 *     unit  - BCM device number
 *     fg    - Field group structure.
 *     fs    - Link to physical slice structure to be cleared
 *     pbmp  - Port bitmap to remove from slice
 *
 * Returns:
 *     BCM_E_NONE      - Success
 *     BCM_E_BUSY      - Entries still in slice, can't clear slice
 */
STATIC int
_field_slice_clear(int unit, _field_group_t *fg,
                   _field_slice_t *fs, bcm_pbmp_t pbmp)
{
    _field_stage_t      *stage_fc;      /* Stage field control structure. */
    _field_control_t    *fc;            /* Field control structure.       */
    bcm_port_t          port;           /* Port iterator.                 */
    uint32              entry_idx;      /* Slice entries iterator.        */ 

    /* Input parameters check. */
    if ((NULL == fs) || (NULL == fg)){
       return (BCM_E_PARAM);
    }
    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Get stage field control structure. */
    BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fs->stage_id, &stage_fc));


    for (entry_idx = 0; entry_idx < fs->entry_count; entry_idx++) {
        if (fs->entries[entry_idx] != NULL &&
            fs->entries[entry_idx]->group->gid == fg->gid) {
            FP_ERR(("FP(unit %d) Error: Entries still in slice=%d.\n", unit, fs->slice_number));
            return (BCM_E_BUSY);
        }
    }

    /* Remove ports from slice's port bit map. */
    BCM_PBMP_ITER(pbmp, port) {
        BCM_PBMP_PORT_REMOVE(fs->pbmp, port);
    }

    /* Clean up group configuration if last group was removed from the slice. */
    if(BCM_PBMP_IS_NULL(fs->pbmp)) {
        /* Clear slice configuration in hw. */
        if (NULL != fc->functions.fp_slice_clear) {
            BCM_IF_ERROR_RETURN(fc->functions.fp_slice_clear(unit, fg, fs));
        }

        fs->group_flags = 0;
        fs->doublewide_key_select = _FP_SELCODE_DONT_CARE;
        fs->src_class_sel = _FP_SELCODE_DONT_CARE;
        fs->dst_class_sel = _FP_SELCODE_DONT_CARE;
        fs->intf_class_sel = _FP_SELCODE_DONT_CARE;
        fs->loopback_type_sel = _FP_SELCODE_DONT_CARE;
        fs->ingress_entity_sel = _FP_SELCODE_DONT_CARE;
        fs->src_entity_sel = _FP_SELCODE_DONT_CARE;        
        fs->dst_fwd_entity_sel = _FP_SELCODE_DONT_CARE;
        fs->fwd_field_sel = _FP_SELCODE_DONT_CARE;
    }

    return (BCM_E_NONE);
}

/*
 * Function: _field_vmap_unused_resources_get
 *
 * Purpose:
 *     Service routine used to retrieve unused virtual groups 
 *     and physical slices
 * Parameter
 *     unit           - (IN) BCM device number. 
 *     vmap           - (IN) Virutal map array.
 *     vmap_size      - (IN) Virtual map size.
 *     unused_groups  - (OUT) Unused virtual groups.
 *     unused_slices  - (OUT) Unused physical slices.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_vmap_unused_resources_get(int unit, _field_virtual_map_t *vmap, 
                                 int vmap_size, uint32 *unused_groups, 
                                 uint32 *unused_slices)
{
    int idx;                   /* Virtual map iteration index. */
    uint32 used_groups = 0;    /* Used virtual groups.         */
    uint32 used_slices = 0;    /* Used physical slices.        */

    /* Input parameters check. */
    if ((NULL == vmap) || (NULL == unused_groups) || (NULL == unused_slices)) {
        return (BCM_E_PARAM);
    }


    /* Iterate over all currently used groups & update bitmap. */
    for (idx = 0; idx < vmap_size; idx++) {
        /* Skip unused virtual priorities. */
        if (vmap[idx].valid == FALSE) {
            continue;
        }

        used_groups |= (1 << vmap[idx].virtual_group);
        used_slices |= (1 << vmap[idx].vmap_key);
    }

    /* Update caller information. */
    *unused_groups = ~used_groups;
    *unused_slices = ~used_slices;

    return (BCM_E_NONE);
}

/*
 * Function: _field_vmap_resource_alloc
 *
 * Purpose:
 *     Service routine used to allocate virutal group/physical
 *     slice from unused resources map.
 * Parameter
 *     unit           - (IN) BCM device number. 
 *     vmap           - (IN) Virutal map array.
 *     vmap_size      - (IN) Virtual map size.
 *     resource       - (IN) Available resources bitmap.
 *     allocated_idx  - (OUT) Allocated index. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_vmap_resource_alloc(int unit, _field_virtual_map_t *vmap,
                           int vmap_size, uint32 *resource,
                           int *allocated_idx)
{
    int idx;                      /* Tcam slices iteration index. */

    /* Input parameters check. */
    if ((NULL == vmap) || (NULL == resource) || (NULL == allocated_idx)) {
        return (BCM_E_PARAM);
    }

    /* Iterate over all currently used groups & update bitmap. */
    for (idx = 0; idx < vmap_size; idx++) {
        if ((*resource) & (1 << idx)) {
            break;
        }
    }

    /* Check if any resources are available. */
    if (idx == vmap_size) {
        return (BCM_E_RESOURCE);
    }

    *resource &= ~(1 << idx);
    *allocated_idx = idx;
    return (BCM_E_NONE);
}

/*
 * Function: _bcm_field_virtual_map_size_get
 *
 * Purpose:
 *     Calculate virtual map size. 
 * Parameters:
 *     unit         - (IN) BCM device number. 
 *     stage_fc     - (IN) Stage field control structure.
 *     vmap_size    - (OUT) Virtual map size.
 * Returns:
 *     BCM_E_XXX
 */
 int 
 _bcm_field_virtual_map_size_get(int unit, _field_stage_t *stage_fc, int *vmap_size) 
{
    _field_control_t *fc;             /* Field control structure. */

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == vmap_size)) {
        return (BCM_E_PARAM);
    }

    /* Find and validate field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));


    /* Virtual map on stage ingress contains includes priority 
       for external slice.  
     */
    if ((_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) &&  \
        (fc->flags & _FP_EXTERNAL_PRESENT)) {
        *vmap_size = stage_fc->tcam_slices + 1;
    } else {
        *vmap_size = stage_fc->tcam_slices;
    }
    return (BCM_E_NONE);
}

/*
 * Function: _field_virtual_map_insert2
 *
 * Purpose:
 *     For chips which support the virtual slice/group feature,
 *     1) Sort groups by priority.  
 *     2) Aggregate expanded slices into virtual group priority.
 * Parameters:
 *     unit           - (IN) BCM device number. 
 *     stage_fc       - (IN) Stage field control structure.
 *     fg             - (IN) Field group structure. 
 *     map_id         - (IN) Virtual map id. 
 *     vmap_key       - (IN) Virtual map key.
 *     virtual_group  - (IN/OUT) Array of up to _FP_PAIR_MAX virtual group ids 
 *                               or -1 if Virtual group id needs to be assigned.
 *     install        - (IN) Perform installation in HW flag.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_virtual_map_insert2(int unit, _field_stage_t *stage_fc,
                          _field_group_t *fg, uint8 map_id, 
                          int vmap_key, int *virtual_group, 
                          int install)
{
    int idx;                      /* Virtual map iteration index.        */
    int idx_tmp;                  /* Temp iteration index.               */
    int sizeof_vmap;              /* Virtual map byte size.              */
    int candidate;                /* Virtual priority candidate group.   */
    int slice_count;              /* Number of slices for each map entry.*/
    int group_installed;          /* Group installation is complete.     */
    _field_control_t *fc;         /* Field control structure.            */
    uint32 unused_groups;         /* Unused virtual groups bitmap.       */  
    uint32 unused_slices;         /* Unused physical slices bitmap       */
                                  /* Updated virtual map.                */
    _field_virtual_map_t vmap_new[_FP_VMAP_SIZE];
                                  /* Original virtual map.               */
    _field_virtual_map_t vmap_orig[_FP_VMAP_SIZE];
    _field_virtual_map_t *vmap;   /* Currently used virtual map.         */
    int even_boundary_constraint = FALSE; /* Flag for double wide slices.*/
    int vmap_size;                /* Virtual map index count.            */
    int rv;                       /* Operation return status.            */

    /* Input parameters check */
    if ((NULL == fg) || (NULL == stage_fc) || (NULL == virtual_group)) {
        return (BCM_E_PARAM);
    }

    /* Find and validate field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

#if defined(BCM_FIREBOLT2_SUPPORT) 
    if (SOC_IS_FIREBOLT2(unit)) {
        /* FB2 supports virtual priority in stage ingress only. */
        if (stage_fc->stage_id != _BCM_FIELD_STAGE_INGRESS) {
            return (BCM_E_NONE);
        }
        /* FB2 double wide group must reside in even virtual priority. */
        even_boundary_constraint = TRUE;
    }
#endif /* BCM_FIREBOLT2_SUPPORT */

    /* Reset new virtual map. */
    sizeof_vmap = _FP_VMAP_SIZE * sizeof(_field_virtual_map_t);
    sal_memset(vmap_new, 0, sizeof_vmap);

    /* Calculate virtual map size. */
    rv = _bcm_field_virtual_map_size_get(unit, stage_fc, &vmap_size); 
    BCM_IF_ERROR_RETURN(rv);

    /* Get unused virtual groups & physical slices */
    sal_memcpy(vmap_orig, stage_fc->vmap[map_id], sizeof_vmap);
    vmap = vmap_orig;
    rv = _field_vmap_unused_resources_get(unit, vmap, vmap_size,
                                          &unused_groups, &unused_slices);
    BCM_IF_ERROR_RETURN(rv);

    group_installed = FALSE;
    /* Fill new virtual map. */
    for (idx = 0; idx < vmap_size;) {
        idx_tmp = idx;
        vmap = vmap_orig;
        rv = _field_min_virtual_priorty_group_get(unit, vmap, vmap_size,
                                                  &idx_tmp, &candidate);
        BCM_IF_ERROR_RETURN(rv);

        if (_FP_INVALID_INDEX != candidate) {
            vmap = vmap_orig + candidate;
            if ((group_installed) || (vmap->priority <= fg->priority)) {
                idx = idx_tmp;
                /* Get number of slices required for this map. */
                rv = _field_group_slice_count_get(vmap->flags, &slice_count);
                BCM_IF_ERROR_RETURN(rv);
                /* Copy map info for each of the slices. */
                for (idx_tmp = 0; idx_tmp < slice_count; idx_tmp++, idx++) {
                    vmap_new[idx] = vmap[idx_tmp];
                    vmap[idx_tmp].valid = FALSE;
                }
                continue;
            } 
        }

        if (FALSE == group_installed) {
            /* New group insertion portion. */
            /* 
             * Increment virtual priority index to meet even boundary
             * constraints. 
             */
            if ((even_boundary_constraint) &&
                (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE)  &&
                (0 != (idx % 2))) {
                idx++;
            }

            /* Get number of slices required for this map. */
            rv = _field_group_slice_count_get(fg->flags, &slice_count);
            BCM_IF_ERROR_RETURN(rv);

            /* Set virtual map info. */ 
            for (idx_tmp = 0; idx_tmp < slice_count; idx_tmp++, idx++) {
                /* Allocate virtual group id. */
                if (-1 == virtual_group[idx_tmp]) {
                    vmap = vmap_orig;
                    rv = _field_vmap_resource_alloc(unit, vmap, vmap_size, 
                                                    &unused_groups,
                                                    &virtual_group[idx_tmp]);
                    BCM_IF_ERROR_RETURN(rv);
                }
                vmap_new[idx].valid = TRUE;
                vmap_new[idx].vmap_key = vmap_key + idx_tmp;
                vmap_new[idx].virtual_group = virtual_group[idx_tmp];
                vmap_new[idx].priority = fg->priority;
                vmap_new[idx].flags = fg->flags;

                unused_slices &= ~(1 << (vmap_key + idx_tmp));
            }
            group_installed = TRUE;
        }
        if (-1 == candidate) {
            /* No more groups to install. */
            break;
        }
    }


    /* Assign distinct virtual group numbers to unused virtual slices */
    vmap = vmap_orig;
    for (idx = 0; idx < vmap_size; idx++) {
        if (vmap_new[idx].valid == TRUE) {
            continue;
        }
        /* Allocated unused virtual group id. */
        rv = _field_vmap_resource_alloc(unit, vmap, vmap_size, 
                                        &unused_groups, &idx_tmp);
        BCM_IF_ERROR_RETURN(rv);
        vmap_new[idx].virtual_group = idx_tmp; 

        /* Allocated unused physical slice. */
        rv = _field_vmap_resource_alloc(unit, vmap, vmap_size,  
                                        &unused_slices, &idx_tmp);
        BCM_IF_ERROR_RETURN(rv);
        vmap_new[idx].vmap_key = idx_tmp; 
    }

    /* Write new map to the slice virtual map. */
    sal_memcpy(stage_fc->vmap[map_id], vmap_new, sizeof_vmap);

    /* 
     * Write the new_fp_virtual_map to H/W, and
     *     copy to stage's fp_virtual_map 
     */
    if (install) {
        rv = fc->functions.fp_write_slice_map(unit, stage_fc);
        BCM_IF_ERROR_RETURN(rv);
    }
#if defined(BROADCOM_DEBUG)
    for (idx = 0; idx < vmap_size; idx++) {
        vmap = stage_fc->vmap[map_id] + idx;
        if (0 == vmap->valid)  {
            continue;
        }
        FP_VVERB(("FP(unit %d) vverb: vmap_id (%d): virutal group (%d)"
                  "physical slice (%d) flags (%d)\n",
                  unit, idx, vmap->virtual_group, 
                  vmap->vmap_key, 
                  vmap->flags));
    }
#endif /* BROADCOM_DEBUG */
    return BCM_E_NONE;
}

/*
 * Function: _field_virtual_map_insert
 *
 * Purpose:
 *     Insert fp group slices 
 * Parameters:
 *     unit           - (IN) BCM device number. 
 *     stage_fc       - (IN) Stage field control structure.
 *     fg             - (IN) Field group structure. 
 *     map_id         - (IN) Virtual map id. 
 *     install        - (IN) Install the map in hw flag.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_virtual_map_insert(int unit, _field_stage_t *stage_fc,
                          _field_group_t *fg, uint8 map_id, 
                          uint8 install)
{
    int  v_group[_FP_PAIR_MAX];  /* Virtual group id.        */
    _field_slice_t *fs;          /* Field slice pointer.     */ 
    int vmap_key;                /* Virtual map key.         */
    int tmp_install;             /* Install map in hw.       */
    int idx;                     /* group iteration index.   */
    int rv;                      /* Operation return status. */

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == fg)) {
        return (BCM_E_PARAM);
    }

    /* Initialize virtual group ids. */
    for (idx = 0; idx < _FP_PAIR_MAX; idx++) {
        v_group[idx] = _FP_INVALID_INDEX;
    }

    /* Get to the last slice. */
    fs = fg->slices;
    while (fs->next != NULL) {
        fs = fs->next;
    }

    while (fs != NULL) {
        tmp_install = ((fs == fg->slices) && (install)) ? TRUE : FALSE;
        vmap_key = (_BCM_FIELD_STAGE_EXTERNAL == fg->stage_id) ? \
                   (_FP_VMAP_SIZE - 1) : fs->slice_number;
        rv = _field_virtual_map_insert2(unit, stage_fc, fg, map_id,
                                        vmap_key, v_group, tmp_install);
        BCM_IF_ERROR_RETURN(rv);
        fs = fs->prev;
    }
    return (BCM_E_NONE);
}

/*
 * Function: _field_virtual_map_remove
 *
 * Purpose:
 *     For chips which support the virtual slice/group feature,
 *     Wipe out groups physical slices from virtual map.
 * Parameters:
 *     unit           - (IN) BCM device number. 
 *     stage_fc       - (IN) Stage field control structure.
 *     map_id         - (IN) Virtual map id. 
 *     vmap_key       - (IN) Virtual map key.
 *     install        - (IN) Perform installation in HW flag.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_virtual_map_remove(int unit, _field_stage_t *stage_fc, uint8 map_id,
                          int vmap_key, int install)
{
    int idx;                           /* Virtual map iteration index.   */
    int idx_tmp;                       /* Temp iteration index.          */
    int slice_count;                   /* Number of slices used by group.*/
    _field_control_t *fc;              /* Field control structure.       */
    uint32 unused_groups;              /* Unused virtual groups bitmap.  */  
    uint32 unused_slices;              /* Unused physical slices bitmap  */
    int rv = BCM_E_NONE;               /* Operation return status.       */
    int v_group[_FP_PAIR_MAX];         /* Virtual group id.              */
    _field_virtual_map_t *vmap = NULL; /* Currently used virtual map.    */
    int vmap_size;                     /* Virtual map size.              */


    /* Find and validate field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

#if defined(BCM_FIREBOLT2_SUPPORT) 
    if (SOC_IS_FIREBOLT2(unit)) {
        /* FB2 supports virtual priority in stage ingress only. */
        if (stage_fc->stage_id != _BCM_FIELD_STAGE_INGRESS) {
            return (BCM_E_NONE);
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT */

    /* Calculate virtual map size. */
    rv = _bcm_field_virtual_map_size_get(unit, stage_fc, &vmap_size); 
    BCM_IF_ERROR_RETURN(rv);


    /* Get virtual group id. */
    for (idx = 0; idx <  _FP_PAIR_MAX; idx++) {
        v_group[idx] = -1;
    }

    for (idx = 0; idx < vmap_size; idx++) {
        vmap = (stage_fc->vmap[map_id]) + idx;
        if (TRUE != vmap->valid) {
            continue;
        }
        if (vmap->vmap_key == vmap_key) {
            break;
        }
    }

    /* Make sure virtual group was found. */
    if (idx == vmap_size) {
        /* No such virtual group. */
        return (rv);
    }

    /* Get group width. */
    rv = _field_group_slice_count_get(vmap->flags, &slice_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Get virtual group ids. */
    for (idx = 0; idx < slice_count; idx++) {
        v_group[idx] = (vmap + idx)->virtual_group;
    }

    /* Mark group maps as invalid. */
    for (idx = 0; idx <  vmap_size; idx++) {
        vmap = stage_fc->vmap[map_id] + idx;
        if (TRUE != vmap->valid) {
            continue;
        }
        for (idx_tmp = 0; idx_tmp < slice_count; idx_tmp++) {
            if (vmap->virtual_group == v_group[idx_tmp]) {
                vmap->valid = FALSE;
            }
        }
    }

    /* Get unused virtual groups & physical slices */
    vmap = stage_fc->vmap[map_id];
    rv = _field_vmap_unused_resources_get(unit, vmap, vmap_size, 
                                          &unused_groups, &unused_slices);
    BCM_IF_ERROR_RETURN(rv);


    /* Assign distinct virtual group numbers to unused virtual slices */
    for (idx = 0; idx < vmap_size; idx++) {
        vmap = (stage_fc->vmap[map_id]) + idx;
        if (vmap->valid == TRUE) {
            continue;
        }
        /* Allocated unused virtual group id. */
        rv = _field_vmap_resource_alloc(unit, vmap, vmap_size, 
                                        &unused_groups, &idx_tmp);
        vmap->virtual_group = idx_tmp; 

        /* Allocated unused physical slice. */
        rv = _field_vmap_resource_alloc(unit, vmap, vmap_size, 
                                        &unused_slices, &idx_tmp);
        vmap->vmap_key = idx_tmp; 
    }


    /* 
     * Write the new_fp_virtual_map to H/W, and copy to stage's fp_virtual_map 
     */
    if (install) {
        rv = fc->functions.fp_write_slice_map(unit, stage_fc);
    } 
#if defined(BROADCOM_DEBUG)
    for (idx = 0; idx < vmap_size; idx++) {
        vmap = stage_fc->vmap[map_id] + idx;
        if (0 == vmap->valid)  {
            continue;
        }
        FP_VVERB(("FP(unit %d) vverb: vmap_id (%d): virutal group (%d)"
                  "physical slice (%d) flags (%d)\n",
                  unit, idx, vmap->virtual_group, 
                  vmap->vmap_key, 
                  vmap->flags));
    }
#endif /* BROADCOM_DEBUG */

    return rv;
}


/*
 * Function: _field_group_vmap_delete
 *
 * Purpose:
 *     For chips which support the virtual slice/group feature,
 *     Wipe out groups physical slices from virtual map.
 * Parameters:
 *     unit           - (IN) BCM device number. 
 *     stage_fc       - (IN) Stage field control structure.
 *     fg             - (IN) Field group structure. 
 *     install        - (IN) Perform installation in HW flag.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_vmap_delete(int unit, _field_stage_t *stage_fc,
                      _field_group_t *fg, int install)
{
    _field_control_t *fc;                    /* Field control structure.*/
    _field_slice_t   *fs;                    /* Field slice structure.  */
    int              idx;                    /* Temp iteration index.   */
    int              rv;                     /* Operation return status.*/

    fs = fg->slices;

    /* Find and validate field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    switch (stage_fc->stage_id) {
      case _BCM_FIELD_STAGE_LOOKUP:
      case _BCM_FIELD_STAGE_EGRESS:
          rv = _field_virtual_map_remove(unit, stage_fc, _FP_VMAP_DEFAULT, 
                                         fs->slice_number, install);
          BCM_IF_ERROR_RETURN(rv);
          break;
      case _BCM_FIELD_STAGE_EXTERNAL:
          idx = (_FP_VMAP_SIZE) - 1;
          /* External slices controlled by stage ingress map. */
          rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, 
                                        &stage_fc);
          BCM_IF_ERROR_RETURN(rv);

          if ((fg->slices)->pkt_type[_FP_EXT_L2]) {
              rv = _field_virtual_map_remove(unit, stage_fc, _FP_EXT_L2,
                                             idx, install);
          } else if ((fg->slices)->pkt_type[_FP_EXT_IP4]) {
              rv = _field_virtual_map_remove(unit, stage_fc, _FP_EXT_IP4,
                                             idx, install);
          } else if ((fg->slices)->pkt_type[_FP_EXT_IP6]) {
              rv = _field_virtual_map_remove(unit, stage_fc, _FP_EXT_IP6,
                                             idx, install);
          } else {
              rv = BCM_E_INTERNAL;
          }
          BCM_IF_ERROR_RETURN(rv);
          break;
      case _BCM_FIELD_STAGE_INGRESS:
          rv = _field_virtual_map_remove(unit, stage_fc, _FP_VMAP_DEFAULT,
                                         fs->slice_number, FALSE);
          BCM_IF_ERROR_RETURN(rv);

          rv = _field_virtual_map_remove(unit, stage_fc, _FP_EXT_IP4,
                                         fs->slice_number, FALSE);
          BCM_IF_ERROR_RETURN(rv);

          rv = _field_virtual_map_remove(unit, stage_fc, _FP_EXT_IP6, 
                                         fs->slice_number, install);
          BCM_IF_ERROR_RETURN(rv);
          break;
      default:
          return BCM_E_INTERNAL;
    }

    return (BCM_E_NONE);
}


/*
 * Function: _field_group_vmap_add
 *
 * Purpose:
 *     For chips which support the virtual slice/group feature,
 *     Add group physical slices to virtual map.
 * Parameters:
 *     unit           - (IN) BCM device number. 
 *     stage_fc       - (IN) Stage field control structure.
 *     fg             - (IN) Field group structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_vmap_add(int unit, _field_stage_t *stage_fc,
                      _field_group_t *fg)
{
    int              rv;              /* Operation return status.*/

    switch (stage_fc->stage_id) {
      case _BCM_FIELD_STAGE_LOOKUP:
      case _BCM_FIELD_STAGE_EGRESS:
          rv = _field_virtual_map_insert(unit, stage_fc, fg, 
                                         _FP_VMAP_DEFAULT, TRUE);
          BCM_IF_ERROR_RETURN(rv);
          break;
      case _BCM_FIELD_STAGE_EXTERNAL:
          /* External slices controlled by stage ingress map. */
          rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, 
                                        &stage_fc);
          BCM_IF_ERROR_RETURN(rv);

          if ((fg->slices)->pkt_type[_FP_EXT_L2]) {
              rv = _field_virtual_map_insert(unit, stage_fc, fg, 
                                             _FP_EXT_L2, TRUE);
          } else if ((fg->slices)->pkt_type[_FP_EXT_IP4]) {
              rv = _field_virtual_map_insert(unit, stage_fc, fg, 
                                             _FP_EXT_IP4, TRUE);
          } else if ((fg->slices)->pkt_type[_FP_EXT_IP6]) {
              rv = _field_virtual_map_insert(unit, stage_fc, fg, 
                                             _FP_EXT_IP6, TRUE);
          } else {
              rv = BCM_E_INTERNAL;
          }
          BCM_IF_ERROR_RETURN(rv);
          break;
      case _BCM_FIELD_STAGE_INGRESS:
          rv = _field_virtual_map_insert(unit, stage_fc, fg,
                                         _FP_VMAP_DEFAULT, FALSE);
          BCM_IF_ERROR_RETURN(rv);

          rv = _field_virtual_map_insert(unit, stage_fc, fg,
                                         _FP_EXT_IP4, FALSE);
          BCM_IF_ERROR_RETURN(rv);

          rv = _field_virtual_map_insert(unit, stage_fc, fg,
                                         _FP_EXT_IP6, TRUE);
          BCM_IF_ERROR_RETURN(rv);
          break;
      default:
          return BCM_E_INTERNAL;
    }

    return (BCM_E_NONE);
}

/*
 * Function: _field_group_free_unused_slices
 *
 * Purpose:
 *     Unallocate group unused slices.
 * Parameters:
 *     unit           - (IN) BCM device number. 
 *     stage_fc       - (IN) Stage field control structure.
 *     fg             - (IN) Field group structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_free_unused_slices(int unit, _field_stage_t *stage_fc,
                                _field_group_t *fg)
{
    _field_slice_t *fs;       /* Field slice structure.        */
    _field_slice_t *fs_next;  /* Field slice structure.        */
    _field_slice_t *fs_ptr;   /* Field slice structure.        */
    uint8          empty;     /* Slice is empty flag.          */
    int            idx;       /* Group slices iteration index. */
    int            remap;     /* Reinstall virtual slice map.  */     
    int            count;     /* Group slices iteration index. */
    int            rv;        /* Operation return status.      */

    /* We never free first group slice. */
    fs = fg->slices->next;
    remap = FALSE;

    while (fs != NULL) {
        fs_next = fs->next;
        rv = _field_slice_is_empty(unit, fs, &empty);
        BCM_IF_ERROR_RETURN(rv);
        if (empty) {
            remap = TRUE;
            BCM_IF_ERROR_RETURN
                (_field_group_slice_count_get(fs->group_flags, &count));

            /* Preserve next slice to continue the loop over group slices. */

            for (idx = 0; idx < count; idx++) {
                /* Remove slice from group slices linked list. */
                fs_ptr = fs + idx;
                if (fs_ptr->prev != NULL) {
                    fs_ptr->prev->next = fs_ptr->next;
                }

                if (fs_ptr->next != NULL) {
                    fs_ptr->next->prev = fs_ptr->prev;
                }

                /* Clear used entries pbmp. */
                rv = _field_slice_clear(unit, fg, fs_ptr, fg->pbmp);
                BCM_IF_ERROR_RETURN(rv);
                fs_ptr->next = fs_ptr->prev = NULL;
            }
        }
        fs = fs_next;
    }

    if (remap) {
        /* Remove the group from virtual map . */
        BCM_IF_ERROR_RETURN(_field_group_vmap_delete(unit, stage_fc, fg, FALSE));
        BCM_IF_ERROR_RETURN(_field_group_vmap_add(unit, stage_fc, fg));
    }

    return (BCM_E_NONE);
}

/*
 * Function: _field_group_uninstall
 *    
 * Purpose:
 *     Uninstall group from all slices. 
 *     
 * Parameters:
 *     unit - (IN)BCM device number.
 *     fg   - (IN)Field group.
 *
 * Returns:
 *     BCM_E_XXX
 */
int
_field_group_uninstall(int unit, _field_group_t *fg)
{
    _field_control_t    *fc;         /* Field control structure. */
    _field_slice_t      *fs;         /* Field slice structure.   */
    _field_slice_t      *temp_fs;    /* Expanded slices iterator.*/
    int                 parts_count; /* Number of entry parts.   */
    uint16              entry_flags; /* Entry part flags.        */
    uint8               slice_number;/* Slices iterator.         */
    int                 rv;          /* Operation return status. */
    int                 idx;         /* Slices iterator.         */


    /* Find and validate field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Get number of entry parts . */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);


    for (idx = parts_count - 1; idx >= 0; idx--) {
        /* Get entry flags. */
        rv = _bcm_field_tcam_part_to_entry_flags(idx, fg->flags, &entry_flags);
        BCM_IF_ERROR_RETURN(rv);

        if (entry_flags & _FP_ENTRY_SECOND_HALF) {
            continue;
        }

        /* Get slice id for entry part */
        rv = _bcm_field_tcam_part_to_slice_number(idx, fg->flags, &slice_number);
        BCM_IF_ERROR_RETURN(rv);

        fs = fg->slices + slice_number;
        while (fs != NULL) {
            /* Clear tertiary slice, if in-use. */
            BCM_IF_ERROR_RETURN(_field_slice_clear(unit, fg, fs, fg->pbmp));
            temp_fs = fs->next;
            if (fs->prev != NULL) {
                fs->prev->next = NULL;
                fs->prev = NULL;
            }
            fs = temp_fs;
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *     _field_group_linked_list_remove
 * Purpose:
 *     Remove field group from unit's groups list 
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     fg       - (IN) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_linked_list_remove(int unit, _field_group_t *fg)
{
    _field_control_t *fc;      /* Field control structure.    */
    _field_group_t   *fg_prev; /* Fied group iterator.        */

    if (NULL == fg) {
        return (BCM_E_PARAM);
    }

    /* Find and validate field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Remove this group from device's linked-list of groups. */
    if (fc->groups == fg) {
        fc->groups = fg->next;
    }
    else {
        fg_prev = fc->groups;
        while (NULL != fg_prev) {
            if (fg_prev->next ==  fg) {
                fg_prev->next = fg->next;
                break;
            }
            fg_prev = fg_prev->next;
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *     _field_group_linked_list_insert
 * Purpose:
 *     Insert new field group into unit's groups list sorted  
 *     by priority & group width.
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     fsm_ptr  - (IN) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_linked_list_insert(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    _field_group_t      *fg;           /* Field group pointer.     */
    _field_group_t      *fg_iter;      /* Field group iterator.    */
    _field_group_t      *fg_iter_prev; /* Field group iterator.    */


    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    fg = fsm_ptr->fg;
    if (NULL == fg) {
         return (BCM_E_PARAM);
    }

    /* Linked list insertion must be done after group mode was 
       decided(after select codes selection stage). On 5682x devices 
       we might need to reselect select codes based on slice availability, 
       to avoid double insertion remove any installed group first. 
     */ 
    BCM_IF_ERROR_RETURN(_field_group_linked_list_remove(unit, fg));

    /* Insert new field group into unit's groups list sorted by priority. */
    fg_iter_prev = fg_iter = fsm_ptr->fc->groups;
    while (fg_iter != NULL)  {
        /* Priority comparison: low to high insertion. */
        if (fg_iter->priority > fg->priority) {
            break;
        }

        /* Group width comparison: wide group first. */
        if (fg_iter->priority ==  fg->priority) {
            if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
                break;
            }

            if ((0 == (fg_iter->flags & _FP_GROUP_SPAN_TRIPLE_SLICE)) &&
                (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE)) {
                break;
            }
        }

        fg_iter_prev = fg_iter;
        fg_iter = fg_iter->next;
    }

    /* Head of the list insertion. */
    if (fg_iter == fg_iter_prev) {
        fg->next = fg_iter;
        fsm_ptr->fc->groups = fg;
    } else {
        fg_iter_prev->next = fg;
        fg->next = fg_iter;
    }
    return (BCM_E_NONE);
}

/*
 * Function: _field_group_deinit
 * Purpose:
 *    Destroy field group structure.
 * Parameters:
 *     unit   - (IN) BCM device number.
 *     fg     - (IN) Allocated group structure. 
 *
 * Returns:
 *     BCM_E_NONE      - Success
 */
STATIC int
_field_group_deinit(int unit, _field_group_t *fg)
{
    _field_control_t *fc;          /* Field control structure.    */
    int idx;                       /* Qualifiers iteration index. */

    if (NULL == fg) {
        return (BCM_E_NONE);
    }

    /* Find and validate field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Uninstall group from every slice. */  
    if (NULL != fg->slices) {
        _field_group_uninstall(unit, fg);
    }

    /* Deallocate group qualifiers list. */  
    for (idx = 0; idx < _FP_MAX_ENTRY_WIDTH; idx++) {
        /* If qualifier set was updated free original qualifiers array. */ 
        BCM_IF_ERROR_RETURN(_bcm_field_group_qualifiers_free(fg, idx));
    }

    /* Decrement the use counts for any UDFs used by the group */
    for (idx = 0; idx < BCM_FIELD_USER_NUM_UDFS; idx++) {
        if (SHR_BITGET(fg->qset.udf_map, idx))  {
            if (fc->udf[idx].use_count > 0) {
                fc->udf[idx].use_count--;
            }
        }
    }

    /* Deallocate group entry array if any. */
    if (NULL != fg->entry_arr) {
        sal_free(fg->entry_arr);
    }

    /* Remove group from units group list. */  
    BCM_IF_ERROR_RETURN(_field_group_linked_list_remove(unit, fg));

    sal_free(fg);
    return (BCM_E_NONE);
}

#ifdef BCM_FIREBOLT_SUPPORT
/*
 * Function:
 *     _field_fb_slice_to_field
 *
 * Purpose:
 *     Determines which FP_SLICE_ENABLEr field corresponds to given slice.
 *
 * Parameters:
 *     slice - slice number
 *     field - (OUT) FP_SLICE_ENABLE register field
 *
 * Returns:
 *     BCM_E_NONE      - Success
 *     BCM_E_PARAM     - slice number out of range
 */
STATIC int
_field_fb_slice_to_field(_field_group_t *fg,
                         int slice, soc_field_t *field)
{
    static soc_field_t _ifp_slice_enable_field[16] = {
                                               FP_LOOKUP_ENABLE_SLICE_0f,
                                               FP_LOOKUP_ENABLE_SLICE_1f,
                                               FP_LOOKUP_ENABLE_SLICE_2f,
                                               FP_LOOKUP_ENABLE_SLICE_3f,
                                               FP_LOOKUP_ENABLE_SLICE_4f,
                                               FP_LOOKUP_ENABLE_SLICE_5f,
                                               FP_LOOKUP_ENABLE_SLICE_6f,
                                               FP_LOOKUP_ENABLE_SLICE_7f,
                                               FP_LOOKUP_ENABLE_SLICE_8f,
                                               FP_LOOKUP_ENABLE_SLICE_9f,
                                               FP_LOOKUP_ENABLE_SLICE_10f,
                                               FP_LOOKUP_ENABLE_SLICE_11f,
                                               FP_LOOKUP_ENABLE_SLICE_12f,
                                               FP_LOOKUP_ENABLE_SLICE_13f,
                                               FP_LOOKUP_ENABLE_SLICE_14f,
                                               FP_LOOKUP_ENABLE_SLICE_15f};
 
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    static soc_field_t _vfp_slice_enable_field[4] = {LOOKUP_ENABLE_SLICE_0f,
                                                     LOOKUP_ENABLE_SLICE_1f,
                                                     LOOKUP_ENABLE_SLICE_2f,
                                                     LOOKUP_ENABLE_SLICE_3f};
    
    static soc_field_t _efp_slice_enable_field[4] = {LOOKUP_ENABLE_SLICE_0f,
                                                     LOOKUP_ENABLE_SLICE_1f,
                                                     LOOKUP_ENABLE_SLICE_2f,
                                                     LOOKUP_ENABLE_SLICE_3f};
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */

    assert(fg != NULL && field != NULL);
    if (_BCM_FIELD_STAGE_INGRESS == fg->stage_id) {
         if (slice < 0 || slice >= COUNTOF(_ifp_slice_enable_field)) {
             return (BCM_E_PARAM);
         }
         *field = _ifp_slice_enable_field[slice];
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    } else if (_BCM_FIELD_STAGE_LOOKUP == fg->stage_id) {
         if (slice < 0 || slice >= COUNTOF(_vfp_slice_enable_field)) {
             return (BCM_E_PARAM);
         }
         *field = _vfp_slice_enable_field[slice];
 
    } else if (_BCM_FIELD_STAGE_EGRESS == fg->stage_id) {
         if (slice < 0 || slice >= COUNTOF(_efp_slice_enable_field)) {
             return (BCM_E_PARAM);
         }
         *field = _efp_slice_enable_field[slice];
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    } else {
         return (BCM_E_INTERNAL);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_fb_slice_enable_set
 *
 * Purpose:
 *     Enables or disables packet lookup on a hardware slice.
 *
 * Parameters:
 *     unit   - BCM device number
 *     slice  - Slice number to enable
 *     enable - enable/disable state of slice
 *
 * Returns:
 *     BCM_E_NONE      - Success
 *     BCM_E_INTERNAL  - SOC read/write error
 *
 * Note:
 *     Calling function is responsible for checking feature availability.
 */
STATIC int
_field_fb_slice_enable_set(int unit, _field_group_t *fg,
                           uint8 slice, int enable)
{
    uint32              reg_val_old, reg_val_new;
    soc_field_t         field;

    FP_VERB(("FP: _field_fb_slice_enable_set(slice=%d, enable=%d)\n",
             slice, enable));

    if (NULL == fg) {
        return (BCM_E_PARAM);
    }
 
    BCM_IF_ERROR_RETURN(_field_fb_slice_to_field(fg, slice, &field));
    enable = (enable ? 1 : 0);
    if (_BCM_FIELD_STAGE_INGRESS == fg->stage_id) {
        SOC_IF_ERROR_RETURN(READ_FP_SLICE_ENABLEr(unit, &reg_val_old));
        reg_val_new = reg_val_old;
        soc_reg_field_set(unit, FP_SLICE_ENABLEr, &reg_val_new, field, enable);
        if (reg_val_new != reg_val_old) {
            BCM_IF_ERROR_RETURN(WRITE_FP_SLICE_ENABLEr(unit, reg_val_new));
        }
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    } else if (_BCM_FIELD_STAGE_LOOKUP == fg->stage_id) {
        SOC_IF_ERROR_RETURN(READ_VFP_SLICE_CONTROLr(unit, &reg_val_old));
        reg_val_new = reg_val_old;
        soc_reg_field_set(unit, VFP_SLICE_CONTROLr, &reg_val_new, 
                          field, enable);
        if (reg_val_new != reg_val_old) {
            SOC_IF_ERROR_RETURN(WRITE_VFP_SLICE_CONTROLr(unit, reg_val_new));
        }  
    } else if (_BCM_FIELD_STAGE_EGRESS == fg->stage_id) {
        SOC_IF_ERROR_RETURN(READ_EFP_SLICE_CONTROLr(unit, &reg_val_old));
        reg_val_new = reg_val_old;
        soc_reg_field_set(unit, EFP_SLICE_CONTROLr, &reg_val_new, 
                          field, enable);
        if (reg_val_new != reg_val_old) {
            BCM_IF_ERROR_RETURN(WRITE_EFP_SLICE_CONTROLr(unit, reg_val_new));
        }  
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT  */
    } else {
         return (BCM_E_INTERNAL);
    }


    return (BCM_E_NONE);
}
#endif /* BCM_FIREBOLT_SUPPORT */


/*
 * Function: 
 *     _field_group_add_selcodes_install
 * Purpose:
 *     Update allocated slice sw controls & 
 *     install slice select codes into hw. 
 * Parameters:

 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_selcodes_install(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    _field_slice_t *fs;                /* Slice pointer.          */
    _field_group_t *fg;                /* Field group pointer.    */
    uint16         entry_flags;        /* Entry lookup flags.     */
    uint8          slice_number;       /* Slices iterator.        */
    int            idx;                /* Slice iteration index.  */
    int            parts_count;        /* Number of entry parts.  */
    int            slice_init;         /* Slice sw init needed.   */
    int            rv;                 /* Operation return status.*/

    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    fg = fsm_ptr->fg;

    /* Check if this is the first group installed in slice. */
    slice_init = BCM_PBMP_IS_NULL(fg->slices[0].pbmp) ? TRUE : FALSE;

    /* Install slice/s select codes. */
    BCM_PBMP_OR(fg->slices[0].pbmp, fg->pbmp); 

    /* Write group parameters to hardware. */
    BCM_IF_ERROR_RETURN(fsm_ptr->fc->functions.fp_group_install(unit, fg));

    /* Get number of entry parts. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    for (idx = parts_count - 1; idx >= 0; idx--) {
        /* Get entry flags. */
        rv = _bcm_field_tcam_part_to_entry_flags(idx, fg->flags, &entry_flags);
        BCM_IF_ERROR_RETURN(rv);

        /* Get slice id for entry part */
        rv = _bcm_field_tcam_part_to_slice_number(idx, fg->flags, &slice_number);
        BCM_IF_ERROR_RETURN(rv);

        /* Get slice pointer. */
        fs = fg->slices + slice_number;

        /* Enable slice. */
        if (0 == (entry_flags & _FP_ENTRY_SECOND_HALF)) {
#ifdef BCM_FIREBOLT_SUPPORT
            if (fsm_ptr->stage_fc->flags & _FP_STAGE_SLICE_ENABLE) { 
                rv = _field_fb_slice_enable_set(unit, fg, fs->slice_number, 1);
                BCM_IF_ERROR_RETURN(rv);
            }
#endif /* BCM_FIREBOLT_SUPPORT */
            /* Set per slice configuration &  number of free entries in the slice.*/
            if (slice_init)  {
                fs->free_count = fs->entry_count;
                if (fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
                    fs->free_count >>= 1;
                }
                /* Set group flags in in slice.*/ 
                fs->group_flags = fg->flags & _FP_GROUP_STATUS_MASK;
            }

            /* Set slice usage by device ports. */
            BCM_PBMP_OR(fs->pbmp, fg->pbmp);
        }
        /* Set source class selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].src_class_sel) {
            fs->src_class_sel = fg->sel_codes[idx].src_class_sel;
        }
        /* Set destination class selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].dst_class_sel) {
            fs->dst_class_sel = fg->sel_codes[idx].dst_class_sel;
        }
        /* Set interface class selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].intf_class_sel) {
            fs->intf_class_sel = fg->sel_codes[idx].intf_class_sel;
        }
        /* Set loopback type/tunnel type selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].loopback_type_sel) {
            fs->loopback_type_sel = fg->sel_codes[idx].loopback_type_sel;
        }
        /* Set ingress entity selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].ingress_entity_sel) {
            fs->ingress_entity_sel = fg->sel_codes[idx].ingress_entity_sel;
        }
        /* Set src entity selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].src_entity_sel) {
            fs->src_entity_sel = fg->sel_codes[idx].src_entity_sel;
        }
        /* Set destination forwarding entity selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].dst_fwd_entity_sel) {
            fs->dst_fwd_entity_sel = fg->sel_codes[idx].dst_fwd_entity_sel;
        }

        /* Set destination forwarding field selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].fwd_field_sel) {
            fs->fwd_field_sel = fg->sel_codes[idx].fwd_field_sel;
        }

        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].aux_tag_1_sel) {
            fs->aux_tag_1_sel = fg->sel_codes[idx].aux_tag_1_sel;
        }

        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].aux_tag_2_sel) {
            fs->aux_tag_2_sel = fg->sel_codes[idx].aux_tag_2_sel;
        }

        /* Set intraslice double wide key selection. */
        if (fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            if ((_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].fpf2) &&
                ((idx == _FP_INTRA_SLICE_PART_1) ||
                 (idx == _FP_INTRA_SLICE_PART_3))) {
                fs->doublewide_key_select = fg->sel_codes[idx].fpf2;
            }
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *     _field_group_add_adjust_virtual_map
 * Purpose:
 *     Update slices virtual priorities map. 
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_adjust_virtual_map(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    _field_group_t   *fg;         /* Field group control structure.  */

    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    /* Initialize group pointer. */
    fg = fsm_ptr->fg;

    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state;

    /*  Update slices virtual priorities map.  */
    if ((soc_feature(unit, soc_feature_field_virtual_slice_group)) &&
        (BCM_PBMP_EQ(fg->slices->pbmp, fg->pbmp))) {
        /* 
         * If this is a first group in a slice 
         * a) allocate virtual group.
         * b) Update slice virtual priority. 
         */
        fsm_ptr->rv = _field_group_vmap_add(unit, fsm_ptr->stage_fc, fg);
    }

    if (BCM_SUCCESS(fsm_ptr->rv)) {
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_UDF_UPDATE;
    } else {
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
    }
    return _field_group_add(unit, fsm_ptr);
}

/*
 * Function: 
 *     _field_group_add_hw_qual_list_get
 * Purpose:
 *     Get qualifiers offset in hw. 
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_hw_qual_list_get(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state; 

   /*
    * Set the FPFx metadata (bit offset, width) for this HW
    * this fills the group's qualifier lists.
    */
    fsm_ptr->rv = fsm_ptr->fc->functions.fp_qual_list_get(unit,
                                                          fsm_ptr->stage_fc,
                                                          fsm_ptr->fg);
    if (BCM_FAILURE(fsm_ptr->rv)) {
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
    } else {
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_ADJUST_VIRTUAL_MAP;
    }
    return _field_group_add(unit, fsm_ptr);
}

/*
 * Function: 
 *     _field_udf_usecount_increment
 *
 * Purpose:
 *     Increment the use counts for any UDFs used
 *
 * Parameters:
 *     fc - unit's field control struct
 *     fg - group's metadata struct
 *
 * Returns:
 *     BCM_E_RESOURCE - Invalid UDF
 *     BCM_E_NONE     - Success
 *
 */
STATIC int
_field_udf_usecount_increment(_field_control_t *fc, _field_group_t *fg)
{
    int                 idx;

    for (idx = 0; idx < BCM_FIELD_USER_NUM_UDFS; idx++) {
        if (SHR_BITGET(fg->qset.udf_map, idx)) {
            fc->udf[idx].use_count++;
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *     _field_group_add_udf_update
 * Purpose:
 *     Update udf usage count.
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_udf_update(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state; 

    /* Increment the use counts for any UDFs used */
    fsm_ptr->rv = _field_udf_usecount_increment(fsm_ptr->fc, fsm_ptr->fg);
    fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;

    return _field_group_add(unit, fsm_ptr);
}

/*
 * Function: _field_group_virtual_priority_validate
 *
 * Purpose:
 *  Verify that ther is no virtual priority conflict between
 *  group & other groups in the slice.
 *
 * Parameters:
 *     unit          - (IN)BCM device number.
 *     stage_fc      - (IN)FP stage control info.
 *     fg            - (IN)FP group
 *     slice_numb    - (IN)Slice number where mode is to be programmed.
 *
 * Returns:
 *     BCM_E_NONE      - Success
 *     BCM_E_CONFIG    - Slice is already programmed with conflicting priority.
 *     BCM_E_XXX       - Any other error.
 */
STATIC int
_field_group_virtual_priority_validate(int unit, _field_stage_t *stage_fc, 
                                       _field_group_t *fg, int slice_numb)
{
    _field_slice_t       *fs;    /* First group slice.          */
    int                  idx;    /* Virtual map iteration index.*/
    _field_virtual_map_t *vmap;  /* Virtual map for stage.      */  

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == fg)) {
        return (BCM_E_PARAM);
    }

    if (slice_numb > stage_fc->tcam_slices) {
        return (BCM_E_PARAM);
    }

    FP_VVERB(("FP(unit %d) vverb: _field_group_virtual_priority_validate"
              "(slice_numb=%d, priority=%d)\n", unit, slice_numb, 
              fg->priority));

    /* If group doesn't care about priority - done. */
    if (BCM_FIELD_GROUP_PRIO_ANY == fg->priority) {
        return (BCM_E_NONE);
    }

    /*
     *  Since we already checked ports & mode it is enough to check 
     *  virtual priority for first slice only. 
     */
    fs = stage_fc->slices + slice_numb;
    if (BCM_PBMP_IS_NULL(fs->pbmp)) {
        /* Slice is not used -> no conflicts. */
        return (BCM_E_NONE);
    }

    /* 
     * If two groups sharing a slice they should have the same priority.
     */
    vmap = stage_fc->vmap[_FP_VMAP_DEFAULT];
    for (idx = 0; idx < stage_fc->tcam_slices; idx++) {
        if (vmap[idx].valid == FALSE) {
            continue;
        } else {
            if (fs->slice_number != vmap[idx].vmap_key) {
                continue;
            }
            if (fg->priority != vmap[idx].priority) {
                return (BCM_E_CONFIG);
            }
        } 
    }
    return (BCM_E_NONE);
}

/*
 * Function: _field_group_ports_validate
 *     
 * Purpose:
 *     Test requested group ports against available ports in the slice or
 *     slices needed by the group.
 *
 *     Test to see if mode is appropriate for device. Basically this means
 *     checking for double and triple wide requests on devices that do not
 *     support it. There are additional range checks, but those should almost
 *     never fail.
 *
 * Parameters:
 *     unit          - (IN)BCM device number
 *     stage_fc      - (IN)Stage FP control info.
 *     slice_base    - (IN)Primary slice number.
 *     flags         - (IN)Flags with group mode (single, double, triple or Auto-wide).
 *     pbmp          - (IN)Bit map of ports that group is requesting.
 *
 * Returns:
 *     BCM_E_CONFIG    - Requested at least one port unavailable on one or more
 *                       slices.
 *     BCM_E_NONE      - Success
 */
STATIC int
_field_group_ports_validate(int unit, const _field_stage_t *stage_fc,
                            const int slice_base, const uint8 flags, const bcm_pbmp_t pbmp)
{
    _field_slice_t     *fs;          /* Field slice structure. */
    bcm_pbmp_t          pbmp_temp;

    FP_VVERB(("FP(unit %d) vverb: _field_group_ports_validate(slice_base=%d, flags=%d)\n", 
              unit, slice_base, flags));

    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    if (flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
        if (slice_base % 4 != 0) {
            FP_ERR(("FP(unit %d) Error: bad slice=%d for triple-mode.\n", unit,
                    slice_base));
            return (BCM_E_PARAM);
        }
        fs = stage_fc->slices + slice_base + 2;
        BCM_PBMP_ASSIGN(pbmp_temp, fs->pbmp);
        BCM_PBMP_AND(pbmp_temp, pbmp);
        if (BCM_PBMP_NOT_NULL(pbmp_temp)) {
            FP_VVERB(("FP(unit %d) vverb: slice=%d in-use.\n", unit, slice_base));
            return (BCM_E_CONFIG);
        }
    }

    if ((flags & _FP_GROUP_SPAN_DOUBLE_SLICE) || (flags & _FP_GROUP_SPAN_TRIPLE_SLICE)) {

        if (slice_base % 2 != 0) {
            FP_ERR(("FP(unit %d) Error: bad slice=%d for double-mode.\n", unit,
                    slice_base));
            return (BCM_E_PARAM);
        }

        fs = stage_fc->slices + slice_base + 1;
        /* If group is intraslice verify that slice is intraslice capable. */
        if (flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)  {
             if (0 == (fs->slice_flags & _BCM_FIELD_SLICE_INTRASLICE_CAPABLE)) {
                 return (BCM_E_CONFIG);
             }
        }

        BCM_PBMP_ASSIGN(pbmp_temp, fs->pbmp);
        BCM_PBMP_AND(pbmp_temp, pbmp);
        if (BCM_PBMP_NOT_NULL(pbmp_temp)) {
            FP_VVERB(("FP(unit %d) vverb: slice=%d in-use.\n", unit, slice_base));
            return (BCM_E_CONFIG);
        }
    }

    fs = stage_fc->slices + slice_base;
    /* If group is intraslice verify that slice is intraslice capable. */
    if (flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)  {
        if (0 == (fs->slice_flags & _BCM_FIELD_SLICE_INTRASLICE_CAPABLE)) {
            return (BCM_E_CONFIG);
        }
    }

    BCM_PBMP_ASSIGN(pbmp_temp, fs->pbmp);
    BCM_PBMP_AND(pbmp_temp, pbmp);
    if (BCM_PBMP_NOT_NULL(pbmp_temp)) {
        FP_VVERB(("FP(unit %d) vverb: slice=%d in-use.\n", unit, slice_base));
        return (BCM_E_CONFIG);
    }

    return (BCM_E_NONE);
}

/*
 * Function: _field_group_slice_mode_validate
 *     
 * Purpose:
 *     Check if group can use the slice e.g.
 *     per slice configuration for other installed groups
 *     doesn't create a conflict.
 * Parameters:
 *     unit      - (IN)BCM device number.
 *     slice_num - (IN)Group slice number. 
 *     fs        - (IN)Slice control structure.
 *     fg        - (IN)Field group structure.
 *
 * Returns:
 *     BCM_E_NONE      - No conflicts
 *     BCM_E_CONFIG    - Slice is already programmed with conflicting mode.
 *     BCM_E_XXX - other errors.
 */
STATIC int
_field_group_slice_mode_validate(int unit, int slice_num, 
                                 _field_slice_t *fs, _field_group_t *fg) 
{
    uint8          slice_number;       /* Slices iterator.        */
    int            idx;                /* Slice iteration index.  */
    int            parts_count;        /* Number of entry parts.  */
    int            rv;                 /* Operation return status.*/

    /* Input parameters check. */
    if ((NULL == fs) || (NULL == fg)) {
        return (BCM_E_PARAM); 
    }

    if (BCM_PBMP_IS_NULL(fs->pbmp)) {
        /* Slice is not used -> no conflicts. */
        return (BCM_E_NONE);
    }

    /* Check for single/double/triple wide mode match. */
    if ((fg->flags & _FP_GROUP_STATUS_MASK) != 
        (fs->group_flags & _FP_GROUP_STATUS_MASK)) {
        return (BCM_E_CONFIG);
    }

    /* Get number of entry parts. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    for (idx = 0; idx < parts_count; idx++) {
        /* Get slice id for entry part */
        rv = _bcm_field_tcam_part_to_slice_number(idx, fg->flags, &slice_number);
        BCM_IF_ERROR_RETURN(rv);

        /* Get slice pointer. */
        fs += slice_number;

        /* Source class selection comparison. */
        if ((_FP_SELCODE_DONT_CARE != fs->src_class_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].src_class_sel) &&
            (fs->src_class_sel != fg->sel_codes[idx].src_class_sel)) { 
            return (BCM_E_CONFIG);
        }

        /* Destination class selection comparison. */
        if ((_FP_SELCODE_DONT_CARE != fs->dst_class_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].dst_class_sel) &&
            (fs->dst_class_sel != fg->sel_codes[idx].dst_class_sel)) { 
            return (BCM_E_CONFIG);
        }
        /* Interface class selection comparison. */
        if ((_FP_SELCODE_DONT_CARE != fs->intf_class_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].intf_class_sel) &&
            (fs->intf_class_sel != fg->sel_codes[idx].intf_class_sel)) {
            return (BCM_E_CONFIG);
        }
        /* Loopback type/Tunnel type selection comparison. */
        if ((_FP_SELCODE_DONT_CARE != fs->loopback_type_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].loopback_type_sel) &&
            (fs->loopback_type_sel != fg->sel_codes[idx].loopback_type_sel)) {
            return (BCM_E_CONFIG);
        }
        /* Ingress entity selection comparison. */
        if ((_FP_SELCODE_DONT_CARE != fs->ingress_entity_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].ingress_entity_sel) &&
            (fs->ingress_entity_sel != fg->sel_codes[idx].ingress_entity_sel)) {
            return (BCM_E_CONFIG);
        }
        /* Src entity selection comparison. */
        if ((_FP_SELCODE_DONT_CARE != fs->src_entity_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].src_entity_sel) &&
            (fs->src_entity_sel != fg->sel_codes[idx].src_entity_sel)) {
            return (BCM_E_CONFIG);
        }
        /* Dstination forwarding entity selection comparison. */
        if ((_FP_SELCODE_DONT_CARE != fs->dst_fwd_entity_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].dst_fwd_entity_sel) &&
            (fs->dst_fwd_entity_sel != fg->sel_codes[idx].dst_fwd_entity_sel)) {
            return (BCM_E_CONFIG);
        }

        /* Dstination forwarding entity selection comparison. */
        if ((_FP_SELCODE_DONT_CARE != fs->fwd_field_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].fwd_field_sel) &&
            (fs->fwd_field_sel != fg->sel_codes[idx].fwd_field_sel)) {
            return (BCM_E_CONFIG);
        }

        if ((_FP_SELCODE_DONT_CARE != fs->aux_tag_1_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].aux_tag_1_sel) &&
            (fs->aux_tag_1_sel != fg->sel_codes[idx].aux_tag_1_sel)) { 
            return (BCM_E_CONFIG);
        }

        if ((_FP_SELCODE_DONT_CARE != fs->aux_tag_2_sel) &&
            (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].aux_tag_2_sel) &&
            (fs->aux_tag_2_sel != fg->sel_codes[idx].aux_tag_2_sel)) { 
            return (BCM_E_CONFIG);
        }

        /* Set intraslice double wide key selection. */
        if (fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            if (((idx == _FP_INTRA_SLICE_PART_1) ||
                 (idx == _FP_INTRA_SLICE_PART_3)) && 
                ((_FP_SELCODE_DONT_CARE != fs->doublewide_key_select) &&
                 (_FP_SELCODE_DONT_CARE != fg->sel_codes[idx].fpf2) &&
                 (fs->doublewide_key_select != fg->sel_codes[idx].fpf2))) {
                return (BCM_E_CONFIG);
            }
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function: _field_group_mode_validate
 *     
 * Purpose:
 *      Check if set of slices are usable for a new group. 
 *
 * Parameters:
 *     unit          - (IN)BCM device number.
 *     stage_fc      - (IN)FP stage control info. 
 *     fg            - (IN)FP group
 *     slice_numb    - (IN)Slice number where mode is to be programmed.
 *
 * Returns:
 *     BCM_E_NONE      - Success
 *     BCM_E_CONFIG    - Slice is already programmed with conflicting mode.
 *     BCM_E_XXX       - Any other error.  
 */
STATIC int
_field_group_mode_validate(int unit, _field_stage_t *stage_fc, 
                           _field_group_t *fg, int slice_numb)
{
    _field_slice_t *fs;
    
    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == fg)) {
       return (BCM_E_PARAM);
    }

    if (slice_numb > stage_fc->tcam_slices) {
       return (BCM_E_PARAM);
    }
    
    FP_VVERB(("FP(unit %d) vverb: _field_group_mode_validate(slice_numb=%d, flags=%d)\n",
              unit, slice_numb, fg->flags));

    /* Confirm that mode will work on specific slice(s). If another group is
     * already defined on slice(s), then the requested mode has to match 
     * the hardware mode. */
    fs = stage_fc->slices + slice_numb;
    
    return _field_group_slice_mode_validate(unit, _FP_INTER_SLICE_PART_2, fs, fg); 
}

/*
 * Function: 
 *     _field_group_add_slice_validate
 * Purpose:
 *     Validate a candidate slice if it fits for a group.
 * Parameters:
 *     unit     - (IN  BCM device number.
 *     stage_fc - (IN) State machine tracking structure. 
 *     fg       - (IN) Field group structure. 
 *     slice_id - (IN) Candidate slice id. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_slice_validate(int unit, _field_stage_t *stage_fc,
                                _field_group_t *fg, int slice_id)
{
    int rv;                       /* Operation return status. */

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == fg)) {
        return (BCM_E_PARAM);
    }

    /* 
     * If this slice belongs to an auto-expanded group, AND
     *     is not the first one of that group,
     *         cannot use it
     */
    if (stage_fc->slices[slice_id].prev != NULL) {
        return (BCM_E_CONFIG);
    }

    /*
     *  Skip the slice if group is intraslice and 
     *  slice is not intraslice capable. 
     */
    if ((fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) && 
        (0 == (stage_fc->slices[slice_id].slice_flags &
               _BCM_FIELD_SLICE_INTRASLICE_CAPABLE))) {
        return (BCM_E_CONFIG);
    }

    /*
     *  Skip the slice if group slice size is small  and 
     *  slice is not of smaller size.
     */
    if ((fg->flags & _FP_GROUP_SELECT_SMALL_SLICE) && 
        (0 == (stage_fc->slices[slice_id].slice_flags &
               _BCM_FIELD_SLICE_SIZE_SMALL))) {
        return (BCM_E_CONFIG);
    }

    /*
     *  Skip the slice if group slice size is large  and 
     *  slice is not of large size.
     */
    if ((fg->flags & _FP_GROUP_SELECT_LARGE_SLICE) && 
        (0 == (stage_fc->slices[slice_id].slice_flags &
               _BCM_FIELD_SLICE_SIZE_LARGE))) {
        return (BCM_E_CONFIG);
    }

    /*
     *  Make sure there is no conflict between groups ports
     *  and other groups in the slice. 
     */
    rv = _field_group_ports_validate(unit, stage_fc, slice_id, 
                                     fg->flags, fg->pbmp);
    BCM_IF_ERROR_RETURN(rv);

    /*
     *  Make sure there is no conflict between 
     *  group & other groups mode. (single/double/triple) 
     *  do not coexist. 
     */
    rv = _field_group_mode_validate(unit, stage_fc, fg, slice_id);
    BCM_IF_ERROR_RETURN(rv);

    /*
     *  Make sure there is no virtual priority conflict between 
     *  group & other groups in the slice. 
     */
    if (soc_feature(unit, soc_feature_field_virtual_slice_group)) { 
        rv = _field_group_virtual_priority_validate(unit, stage_fc, 
                                                    fg, slice_id);
        BCM_IF_ERROR_RETURN(rv);
    }

    return (BCM_E_NONE);
}
/*
 * Function: 
 *     _field_virtual_priority_support
 * Purpose:
 *     Check if device supports virtual priority. 
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     stage_fc - (IN) Field stage control.
 *     support  - (OUT) TRUE supports virtual priority.
 *                      FALSE otherwise.
 * Returns:
 *     BCM_E_XXX 
 */
STATIC int
_field_virtual_priority_support(int unit, _field_stage_t *stage_fc, int *support)
{

    /* Input parameters check. */
    if ((NULL == stage_fc) ||  (NULL == support)){
        return (BCM_E_PARAM);
    }

    if (0 == soc_feature(unit, soc_feature_field_virtual_slice_group)) {
        *support = FALSE;
    } else if (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
        *support = TRUE;
    } else if (SOC_IS_FIREBOLT2(unit)) {
        *support = FALSE;
    } else {
        *support = TRUE;
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *     _field_group_add_slice_allocate
 * Purpose:
 *     Allocate slice for a new group.
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_slice_allocate(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    _field_group_t      *fg;             /* Field group pointer.          */
    _field_stage_t      *stage_fc;       /* Stage field control.          */
    int                 slice_id;        /* Slices iterator.              */
    int                 virtual_priority = FALSE;/* Virtual priority support flag.*/

    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    /* Group pointer initialization. */ 
    fg = fsm_ptr->fg;
    stage_fc = fsm_ptr->stage_fc;
    slice_id = -1;

    _field_virtual_priority_support(unit, stage_fc, &virtual_priority);
    
    if ((_BCM_FIELD_STAGE_EXTERNAL == fg->stage_id)) {
        /* External slices mapped 1-1 to selected keys.*/
        fg->slices = stage_fc->slices + fg->sel_codes[0].extn;
        slice_id = fg->sel_codes[0].extn;
    } else if ((BCM_FIELD_GROUP_PRIO_ANY == fsm_ptr->priority) || (virtual_priority)) {
        /* If not specified, generate a priority. */   
        for (slice_id = 0; slice_id < stage_fc->tcam_slices; slice_id++) {
            fsm_ptr->rv = _field_group_add_slice_validate(unit, stage_fc, 
                                                          fg, slice_id);
            if(BCM_SUCCESS(fsm_ptr->rv)) {
                break;
            }
        }
        /* Check if allocation was successful. */
        if (slice_id == stage_fc->tcam_slices) {
            fsm_ptr->rv = (BCM_E_RESOURCE);
        }
    } else {
        if ((fsm_ptr->priority < 0) || 
            (fsm_ptr->stage_fc->tcam_slices <= fsm_ptr->priority)) {
            FP_ERR(("FP(unit %d) Error: pri=%d out-of-range.\n", unit, fsm_ptr->priority));
            fsm_ptr->rv = BCM_E_PARAM;
        } else {
            slice_id = fsm_ptr->priority;
            fsm_ptr->rv = _field_group_add_slice_validate(unit, stage_fc, 
                                                          fg, slice_id);
        }
    }

    if (BCM_FAILURE(fsm_ptr->rv)) {
        /* Different select codes might help for 5682x devices. */
        if ((soc_feature(unit, soc_feature_two_ingress_pipes)) &&
            (fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) && 
            ((0 == (fsm_ptr->priority % 2)) ||
             (BCM_FIELD_GROUP_PRIO_ANY == fsm_ptr->priority))) {
            fsm_ptr->rv = (BCM_E_NONE);
            fsm_ptr->flags &= ~_BCM_FP_GROUP_ADD_INTRA_SLICE;
            fg->flags &= ~_FP_GROUP_INTRASLICE_DOUBLEWIDE;
            fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET;
        } else if ((fsm_ptr->fsm_state_prev !=
                    _BCM_FP_GROUP_ADD_STATE_CAM_COMPRESS) && virtual_priority) {
            fsm_ptr->rv = (BCM_E_NONE);
            fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_CAM_COMPRESS;
        } else {
            fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
        }
    } else {
        fg->slices = stage_fc->slices + slice_id;
        fsm_ptr->rv = _field_group_add_selcodes_install(unit, fsm_ptr);
        if (BCM_SUCCESS(fsm_ptr->rv)) {
            fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_HW_QUAL_LIST_GET;
        } else {
            fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
        }
    }
    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = _BCM_FP_GROUP_ADD_STATE_SLICE_ALLOCATE; 
    return _field_group_add(unit, fsm_ptr);
}

/*
 * Function: _field_group_compress
 *
 * Purpose:
 *     Compress filed group entries, 
 *     in order to free slices used by the group.
 * Paramters:
 *     unit     - (IN) BCM device number
 *     fg       - (IN) Field group structure
 *     stage_fc - (IN) Stage field control structure. 
 * Returns:
 *     BCM_E_XXX
 */

STATIC int
_field_group_compress(int unit, _field_group_t *fg,
                      _field_stage_t *stage_fc)
{
    _field_slice_t       *fs; /* Field slice structure.         */
    _field_slice_t      *efs; /* Slice that contains free slots.*/
    int                 eidx; /* Empty slot index.              */
    int                  idx; /* Slice iteration index.         */
    int             tmp_idx1; /* Slice entry index 1.           */
    int             tmp_idx2; /* Slice entry index 2.           */
    int             slice_sz; /* Number of entries in a slice.  */
    int                   rv; /* Operation return status.       */

    /* Input parameters check. */
    if (NULL == fg) {
        return (BCM_E_PARAM);
    }

    /* Stage External doesn't require compression. */
    if (_BCM_FIELD_STAGE_EXTERNAL == fg->stage_id) {
        return (BCM_E_NONE);
    }

    /* Get group slice pointer. */
    fs = fg->slices;

    efs = NULL;
    eidx = -1;
    while (NULL != fs) {
        _BCM_FIELD_ENTRIES_IN_SLICE(fg, fs, slice_sz);
        for (idx = 0; idx < slice_sz; idx ++)  {
            /* Find an empty slot. */
            if (NULL == fs->entries[idx]) {
                if (NULL == efs) {
                    efs = fs;
                    eidx = idx;
                }
                continue;
            }

            if (NULL != efs) {
                rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc, efs->slice_number, 
                                                         eidx, &tmp_idx1);
                BCM_IF_ERROR_RETURN(rv);

                rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc, fs->slice_number, 
                                                         idx, &tmp_idx2);
                BCM_IF_ERROR_RETURN(rv);

                rv = _field_entry_move(unit, fs->entries[idx], (tmp_idx1 - tmp_idx2));
                BCM_IF_ERROR_RETURN(rv);
                fs = efs;
                idx = eidx;
                efs = NULL;
                eidx = -1;
                _BCM_FIELD_ENTRIES_IN_SLICE(fg, fs, slice_sz);
            }
        }
        fs = fs->next;
    }
    rv = _field_group_free_unused_slices(unit, stage_fc, fg);
    return (rv);
}


/*
 * Function: 
 *     _field_stage_groups_compress
 * Purpose:
 *     Compress stage groups to free room for inserted group.
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     fc        - (IN) Field control structure.    
 *     stage_fc  - (IN) Stage field control. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_stage_groups_compress(int unit, _field_control_t *fc, 
                             _field_stage_t *stage_fc)
{
    _field_group_t *fg;          /* Field group structure. */

    /* Input parameters check. */
    if ((NULL == fc) || (NULL == stage_fc)) {
        return (BCM_E_PARAM);
    }

    /* Compress expanded groups. */
    for (fg = fc->groups; fg != NULL; fg = fg->next) {
        /* Skip other stages. */
        if (fg->stage_id != stage_fc->stage_id) {
            continue;
        }

        /* Skip new group. */ 
        if (NULL == fg->slices) {
            continue; 
        }

        /* Ignore not expanded groups. */ 
        if (NULL == fg->slices->next)  {
            continue; 
        }

        /* Best effort to compress expanded virtual groups. */
        _field_group_compress(unit, fg, stage_fc);
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *     _field_group_add_cam_compress
 * Purpose:
 *     Compress other groups to free room for inserted group.
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_cam_compress(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state; 

    /* Compress expanded groups. */
    BCM_IF_ERROR_RETURN 
        (_field_stage_groups_compress(unit, fsm_ptr->fc, fsm_ptr->stage_fc));

    fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SLICE_ALLOCATE;
    return _field_group_add(unit, fsm_ptr);
}

/*
 * Function:
 *     _field_group_add_initialize
 * Purpose:
 *     Perform fsm initialization & execute basic checks
 *     required before field group creation.
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure.
 * Returns:
 *     BCM_E_XXX.
 */
STATIC int
_field_group_add_initialize(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    
    _field_stage_id_t stage = _BCM_FIELD_STAGE_INGRESS; /* Group pipeline stage id.*/
    _field_group_t      *fg_temp; /* Existing field group pointer. */

    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state; 

    /* Group IDs must be unique within a unit. */
    if(BCM_SUCCESS(_field_group_get(unit, fsm_ptr->group_id, &fg_temp))) {
        FP_ERR(("FP(unit %d) Error: group=%d already exists.\n", 
                unit, fsm_ptr->group_id));
        fsm_ptr->rv = (BCM_E_EXISTS);
    }

    /* Get field stage control pointer. */
    if (BCM_SUCCESS(fsm_ptr->rv)) {
        fsm_ptr->rv = _field_control_get(unit, &fsm_ptr->fc);
    }

    /* Get pipeline stage from qualifiers set. */
    if (BCM_SUCCESS(fsm_ptr->rv)) {
        fsm_ptr->rv = _field_group_stage_get(unit, &fsm_ptr->qset, &stage);
    }

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    /* Allow intraslice select codes if they are supported by the stage. */
    if (BCM_SUCCESS(fsm_ptr->rv)  &&
        soc_feature(unit, soc_feature_field_intraslice_double_wide) &&
        (fsm_ptr->fc->flags & _FP_INTRASLICE_ENABLE) && 
        (_BCM_FIELD_STAGE_EGRESS != stage) &&
        (_BCM_FIELD_STAGE_EXTERNAL != stage)) {
            /* We might try intraslice group. */
        if ((!SOC_IS_TD_TT(unit)) ||
            (SOC_IS_TD_TT(unit) && (_BCM_FIELD_STAGE_LOOKUP == stage))) {
            /* For TD and TT Intra-slice mode supported only for VFP */
            fsm_ptr->flags |= _BCM_FP_GROUP_ADD_INTRA_SLICE;
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */

    /* Get field stage control pointer. */
    if (BCM_SUCCESS(fsm_ptr->rv)) {
        fsm_ptr->rv  = _field_stage_control_get(unit, stage, &fsm_ptr->stage_fc);
    }

#ifdef BCM_TRIUMPH_SUPPORT
    /* _bcmFieldQualifyData2 is valid only for external stage on Triumph */
    if (SOC_IS_TRIUMPH(unit) || SOC_IS_TRIUMPH2(unit)) {
        if ((BCM_FIELD_QSET_TEST(fsm_ptr->qset, 
                bcmFieldQualifyStageExternal) == 0) &&
            (BCM_FIELD_QSET_TEST(fsm_ptr->qset, 
                _bcmFieldQualifyData2))) {
            BCM_FIELD_QSET_REMOVE_INTERNAL(fsm_ptr->qset, 
                _bcmFieldQualifyData2);
        }
    }
#endif /* !BCM_TRIUMPH_SUPPORT || BCM_TRIUMPH2_SUPPORT */

    /* Verify that requested qualifiers set is supported by stage. */
    if (BCM_SUCCESS(fsm_ptr->rv)) {
        if (FALSE == _field_qset_is_subset(&fsm_ptr->qset, 
                                           &fsm_ptr->stage_fc->_field_supported_qset)) {
            FP_ERR(("FP(unit %d) Error: Qualifier set is not supported by the device.\n", unit));
            fsm_ptr->rv = BCM_E_UNAVAIL;
        }
    }

    if (BCM_FAILURE(fsm_ptr->rv)) {
        /* Error occured -> clean up.. */
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
    } else {
        /* Proceed to group allocation stage. */
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_ALLOC;
    }
    return _field_group_add(unit, fsm_ptr);
}

/*
 * Function: 
 *     _field_group_add_alloc
 * Purpose:
 *     Allocate & initialize field group structure.
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure.
 * Returns:
 *     BCM_E_XXX.
 */
STATIC int
_field_group_add_alloc(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    int                 idx;         /* Misc iterator.           */
    int                 mem_sz;      /* Allocated memory size.   */
    _field_group_t      *fg = NULL;  /* New group info.          */


    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state; 

    /* Allocate & initialize memory for field group. */
    mem_sz = sizeof(_field_group_t);
    _FP_XGS3_ALLOC(fg, mem_sz, "field group");
    if (NULL == fg) {
        FP_ERR(("FP(unit %d) Error:Allocation failure for _field_group_t\n", unit));
        fsm_ptr->rv = BCM_E_MEMORY;
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
        return _field_group_add(unit, fsm_ptr);
    }


    /* Initialize group structure. */
    fg->gid            = fsm_ptr->group_id;
    fg->stage_id       = fsm_ptr->stage_fc->stage_id;
    fg->qset           = fsm_ptr->qset;
    fg->pbmp           = fsm_ptr->pbmp;
    fg->priority       = fsm_ptr->priority;

    /* Initialize group status. */
    fsm_ptr->rv = _bcm_field_group_status_init(unit, &fg->group_status);
    if (BCM_FAILURE(fsm_ptr->rv)) {
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
        return _field_group_add(unit, fsm_ptr);
    }

    /* Clear the group's select codes and its slice Qsets. */
    for (idx = 0; idx < _FP_MAX_ENTRY_WIDTH; idx++) { 
        _FIELD_SELCODE_CLEAR(fg->sel_codes[idx]);
    }

    /* By default mark group as active. */
    fg->flags |= _FP_GROUP_LOOKUP_ENABLED;

    /* Set special group flags. */
    if (fsm_ptr->flags & _BCM_FP_GROUP_ADD_WLAN) {
        fg->flags |= _FP_GROUP_WLAN;
    }

    /* Set slice size selection group flags. */
    if (fsm_ptr->flags & _BCM_FP_GROUP_ADD_SMALL_SLICE) {
        fg->flags |= _FP_GROUP_SELECT_SMALL_SLICE;
    } else if (fsm_ptr->flags & _BCM_FP_GROUP_ADD_LARGE_SLICE) {
        fg->flags |= _FP_GROUP_SELECT_LARGE_SLICE;
    }

    /* Set allocated pointer to FSM structure. */
    fsm_ptr->fg = fg;

    /* Update group qset with internal qualifiers. */
    fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_QSET_UPDATE;

    return _field_group_add(unit, fsm_ptr);
}

/*
 * Function: 
 *     _field_group_add_qualify_in_ports
 * Purpose:
 *     Update group application requested qset 
 *     if group is restricted to subset of device ports.
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fg       - (IN/OUT) Field Group pointer.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_qualify_in_ports(int unit, _field_group_t *fg)
{
    bcm_port_config_t  port_config;/* Device port config.    */
    bcm_pbmp_t  pbmp_temp;       /* Port bitmap buffer.      */
    int         count;           /* Number of ports in PBMP. */
    int         qual_in_ports;   /* Qualify InPorts flag.    */


    /* Input parameters check. */
    if (NULL == fg) {
        return (BCM_E_PARAM);
    }

    /* Read device port configuration. */ 
    BCM_IF_ERROR_RETURN(bcm_esw_port_config_get(unit, &port_config));

    /*
     *  If group active on on all ports no InPort/InPorts 
     *  qualification  is required. 
     */
    BCM_PBMP_ASSIGN(pbmp_temp, port_config.all);
    if (BCM_PBMP_EQ(fg->pbmp, pbmp_temp)) {
        return (BCM_E_NONE);
    }

    if (_BCM_FIELD_STAGE_INGRESS != fg->stage_id) {
        return (BCM_E_RESOURCE);
    }

    qual_in_ports = TRUE; 
    /*
     * If there's only 1 port and device capable efficiently 
     * qualify on source port use InPort qualifier in stead of InPorts
     */ 
    BCM_PBMP_COUNT(fg->pbmp, count);
    if ((count == 1) && (!soc_feature(unit, soc_feature_table_hi))) {
        if (soc_feature(unit, soc_feature_field_multi_stage)) {
            BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyInPort);
            qual_in_ports = FALSE;
        } else if (SOC_MEM_FIELD_VALID(unit, FP_TCAMm, SOURCE_PORT_NUMBER_MASKf)) {
            /*
             *  In Order to qualify on a single Higig port - 
             *  Higig quailifier must be  present in each rule.
             */
            BCM_PBMP_ASSIGN(pbmp_temp, fg->pbmp);
            BCM_PBMP_AND(pbmp_temp, PBMP_HG_ALL(unit));
            if (BCM_PBMP_IS_NULL(pbmp_temp)) {
                BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyInPort);
                qual_in_ports = FALSE; 
            }
        }
    }
    if (qual_in_ports) {
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyInPorts);
    }
    return (BCM_E_NONE);
}

/*
 * Function: 
 *     _field_group_qset_update
 * Purpose:
 *     Update application requested qset with internal qualifiers.
 * Parameters:
 *     unit  - (IN)     BCM device number.
 *     fg    - (IN/OUT) Field group structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_qset_update(int unit, _field_group_t *fg)
{
    /* Input parameters check. */
    if (NULL == fg) {
        return (BCM_E_PARAM);
    }

    /* All ingress devices implicitly have bcmFieldQualifyStage in Qsets.*/
    if (_BCM_FIELD_STAGE_INGRESS == fg->stage_id) {
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyStage);
    }

    /*
     * LookupStatus qualifiers was deprecated & replaced 
     * with bcmFieldQualifyVlanTranslationHit, 
     *      bcmFieldQualifyForwardingVlanValid
     *      bcmFieldQualifyIngressStpState
     *      bcmFieldQualifyL2SrcHit
     *      bcmFieldQualifyL2SrcStatic
     *      bcmFieldQualifyL2DestHit
     *      bcmFieldQualifyL2StationMove
     *      bcmFieldQualifyL2CacheHit
     *      bcmFieldQualifyL3SrcHostHit
     *      bcmFieldQualifyL3DestHostHit
     *      bcmFieldQualifyL3DestRouteHit
     *      bcmFieldQualifyIpmcStarGroupHit
     *      bcmFieldQualifyMyStationHit
     *      bcmFieldQualifyDosAttack
     *      bcmFieldQualifyL3Routable
     *      bcmFieldQualifyTunnelTerminated
     */
    if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyLookupStatus)) {
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyVlanTranslationHit);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyForwardingVlanValid);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyIngressStpState);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL2SrcHit);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL2SrcStatic);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL2DestHit);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL2StationMove);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL2CacheHit);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL3SrcHostHit);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL3DestHostHit);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL3DestRouteHit);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyIpmcStarGroupHit);
        if (soc_feature(unit, soc_feature_field_qual_my_station_hit)) {
            BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyMyStationHit);
        }
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL3Routable);

#ifdef BCM_TRIUMPH2_SUPPORT /* BCM_TRIUMPH2_SUPPORT */
        if (SOC_IS_TRIUMPH2(unit) || SOC_IS_TD_TT(unit) ||
            SOC_IS_APOLLO(unit) || SOC_IS_VALKYRIE2(unit) ||
            SOC_IS_ENDURO(unit) || SOC_IS_KATANA(unit)) {
            BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyMplsTerminated);
        } else 
#endif /* !BCM_TRIUMPH2_SUPPORT */
        {
            BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyTunnelTerminated);
        }
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyDosAttack);
    }

    /*
     * PacketFormat qualifiers was deprecated & replaced 
     * with L2Format ,  VlanFormat , IpType.
     */
    if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyPacketFormat)) {
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyL2Format);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyVlanFormat);
    }

    /*
     * Vlan qualifiers ared extended to Id/Cfi/Pri
     */
    if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyOuterVlan)) {
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyOuterVlanId);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyOuterVlanPri);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyOuterVlanCfi);
    }
    if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyInnerVlan)) {
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyInnerVlanId);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyInnerVlanPri);
        BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyInnerVlanCfi);
    }

    /*
     * Automatically include IpType 
     * if the qset contains PacketFormat/Ip4/Ip6.
     * FB2 stage egress and stage external are an exception. 
     */
    if (_BCM_FIELD_STAGE_EXTERNAL != fg->stage_id) { 
        if (
#if defined (BCM_FIREBOLT2_SUPPORT)
                ((0 == SOC_IS_FIREBOLT2(unit)) || 
                 (_BCM_FIELD_STAGE_EGRESS != fg->stage_id)) &&
#endif /* BCM_FIREBOLT2_SUPPORT */
                ((BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyPacketFormat)) ||
                 (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyIp4)) ||
                 (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyIp6)))) {
            BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyIpType);
        }
    }

#if defined(BCM_FIREBOLT2_SUPPORT)
    if (SOC_IS_FIREBOLT2(unit)) {
        /* Device doesn't support qualification on IP without version. */
        if  ((BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyIp4)) &&
             (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyIp6))) {
            return  (BCM_E_RESOURCE);
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT */

    /* 
     * Add qualification on InPorts/InPort in case group applicable only 
     * to part of the ports. 
     */
    BCM_IF_ERROR_RETURN(_field_group_add_qualify_in_ports(unit, fg));

    return (BCM_E_NONE);
}

/*
 * Function: 
 *     _field_group_add_qset_update
 * Purpose:
 *     Update application requested qset with internal qualifiers.
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_qset_update(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    if (NULL == fsm_ptr->fg) {
        fsm_ptr->rv = (BCM_E_PARAM);
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
        return _field_group_add(unit, fsm_ptr);
    }

    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state; 

    /* Update group qset with internal qualifiers. */
    fsm_ptr->rv = _field_group_qset_update(unit, fsm_ptr->fg);

    if (BCM_FAILURE(fsm_ptr->rv)) {
        /* Qset verification/modification failed - clean up. */
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
    } else {
        /* Proceed to select codes selection. */
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET;
    }
    return _field_group_add(unit, fsm_ptr);
}


/*
 * Function: 
 *     _field_group_add_sel_codes_get
 * Purpose:
 *     Calculate the FPFx select codes from a qualifier set and group mode.
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_sel_codes_get(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    _field_group_t      *fg;                 /* Field group pointer.     */
    int                orig_group_flags;     /* Original group flags.    */


    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    if (NULL == fsm_ptr->fg) {
        fsm_ptr->rv = (BCM_E_PARAM);
    }

    /* Check if requested mode is supported by device. */
    switch (fsm_ptr->mode) {
      case bcmFieldGroupModeQuad: 
          if (0 == soc_feature(unit, soc_feature_field_intraslice_double_wide)) {
              fsm_ptr->rv = (BCM_E_RESOURCE);
          }
          break;
      case bcmFieldGroupModeTriple:
          if (soc_feature(unit, soc_feature_field_intraslice_double_wide)) {
              fsm_ptr->rv = (BCM_E_RESOURCE);
          }
#ifdef BCM_TRIDENT_SUPPORT
          if (SOC_IS_TD_TT(unit))
          {
              fsm_ptr->rv = (BCM_E_UNAVAIL);
          }
#endif
          /* Fall through. */
      case bcmFieldGroupModeDouble: 
          if (0 == soc_feature(unit, soc_feature_field_wide)) {
              fsm_ptr->rv = (BCM_E_RESOURCE);
          }
          break;
      default:
          break;
    }
    if (BCM_FAILURE(fsm_ptr->rv)) {
        fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state;
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
        return _field_group_add(unit, fsm_ptr);
    }

    /* Group pointer initialization. */ 
    fg = fsm_ptr->fg;
    
    fsm_ptr->rv = BCM_E_RESOURCE;
    orig_group_flags = fg->flags;


    /* Allocate & initialize memory for field group. */
    if (fsm_ptr->mode == bcmFieldGroupModeAuto)
    {
        FP_VVERB(("Group mode auto.\n"));

        /* For Auto mode, try Single, Double, then Triple. */
        /* Single wide non intra slice selection. */
        if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
            FP_VVERB(("Trying single...\n"));
            fg->flags = (orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE);
            fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
        }

        /* Double wide intra slice selection. */
        if ((BCM_FAILURE(fsm_ptr->rv) && 
             (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE))) {
            if (soc_feature(unit, soc_feature_field_intraslice_double_wide)) {
                FP_VVERB(("Trying intra...\n"));
                fg->flags = (orig_group_flags |
                             _FP_GROUP_SPAN_SINGLE_SLICE |
                             _FP_GROUP_INTRASLICE_DOUBLEWIDE);
                fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
            }
        }

        /* Double wide inter slice selection. */
        if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
            if (BCM_FAILURE(fsm_ptr->rv)) {
                FP_VVERB(("Trying double...\n"));
                fg->flags = (orig_group_flags | _FP_GROUP_SPAN_DOUBLE_SLICE);
                fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
            }
        }

        /* Quad wide inter & intra slice selection. */
        if ((BCM_FAILURE(fsm_ptr->rv) &&
             (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE))) {
            if (soc_feature(unit, soc_feature_field_intraslice_double_wide)) {
                FP_VVERB(("Trying quad...\n"));
                fg->flags = (orig_group_flags |
                             _FP_GROUP_SPAN_DOUBLE_SLICE |
                             _FP_GROUP_INTRASLICE_DOUBLEWIDE);
                fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
            }
        }

        /* Triple wide inter slice selection. */
        if ((0 == soc_feature(unit, soc_feature_field_intraslice_double_wide)) && 
            (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) &&
            (!SOC_IS_TD_TT(unit))) {
            if (BCM_FAILURE(fsm_ptr->rv)) {
                FP_VVERB(("Trying triple...\n"));
                fg->flags = (orig_group_flags | _FP_GROUP_SPAN_TRIPLE_SLICE);
                fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
            }
        }
    } else {
        switch (fsm_ptr->mode) {
          case bcmFieldGroupModeSingle:
              /* Single wide non intra slice selection. */
              if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
                  fg->flags = (orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE);
                  fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
              }
              break;
          case bcmFieldGroupModeDouble:
              /* Double wide intra slice selection. */
              if ((soc_feature(unit, soc_feature_field_intraslice_double_wide) &&
                   (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE))) {
                  fg->flags = (orig_group_flags |
                               _FP_GROUP_SPAN_SINGLE_SLICE |
                               _FP_GROUP_INTRASLICE_DOUBLEWIDE);
                  fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
              }
              /* Double wide inter slice selection. */
              if ((BCM_FAILURE(fsm_ptr->rv)) &&
                  (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY))) {
                  fg->flags = (orig_group_flags | _FP_GROUP_SPAN_DOUBLE_SLICE);
                  fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
              }
              break;
          case bcmFieldGroupModeTriple:
              /* Triple wide inter slice selection. */
              if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
                  fg->flags = (orig_group_flags | _FP_GROUP_SPAN_TRIPLE_SLICE);
                  fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
              }
              break;
          case bcmFieldGroupModeQuad:
              if ((soc_feature(unit, soc_feature_field_intraslice_double_wide) &&
                   (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE))) {
                  fg->flags = (orig_group_flags | _FP_GROUP_SPAN_DOUBLE_SLICE |
                               _FP_GROUP_INTRASLICE_DOUBLEWIDE);
                  fsm_ptr->rv = _field_selcode_assign(unit, fg->qset, 1, fg);
              } 
              break;
          default:
              fsm_ptr->rv = (BCM_E_PARAM);
        }
    }

    if (BCM_FAILURE(fsm_ptr->rv)) {
        FP_VVERB(("No success so far.\n"));
        /* No luck so far - try different alternative qset if possible. */
        if ((BCM_E_RESOURCE == fsm_ptr->rv) &&
            (_BCM_FP_GROUP_ADD_STATE_QSET_UPDATE == fsm_ptr->fsm_state_prev)) {
            fsm_ptr->rv = (BCM_E_NONE);
            fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_QSET_ALTERNATE;
        } 
    } else {
#ifdef BCM_TRIUMPH2_SUPPORT /* BCM_TRIUMPH2_SUPPORT */
        int i, ingress_entity = 0;
#endif /* !BCM_TRIUMPH2_SUPPORT */

        FP_VVERB(("Configuration found...\n"));
        /* Check if unit supports wide rules. */
        if ((!soc_feature(unit, soc_feature_field_wide)) &&
            (!(fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE)))
        {
            FP_VVERB(("Double not supported.\n"));
            fsm_ptr->rv = (BCM_E_UNAVAIL);
        }

#ifdef BCM_TRIUMPH2_SUPPORT /* BCM_TRIUMPH2_SUPPORT */
        /* 
         * Check which configuration of SrcMplsGport/SrcMimGport
         * is in use.
         */
        for (i = 0; i < _FP_MAX_ENTRY_WIDTH; i++) {
            if ((fg->sel_codes[i].ingress_entity_sel == 
                    _bcmFieldFwdEntityMimGport) ||
                (fg->sel_codes[i].ingress_entity_sel == 
                    _bcmFieldFwdEntityMplsGport) ||
                (fg->sel_codes[i].ingress_entity_sel ==
                    _bcmFieldFwdEntityWlanGport)) {
                ingress_entity = 1;
                break;
            }
        }

        /* Adjust for SvpValid where applicable */
        if (soc_feature(unit, soc_feature_mim) && 
            BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifySrcMimGport) && 
            !BCM_FIELD_QSET_TEST(fg->qset, _bcmFieldQualifySvpValid) &&
            (1 == ingress_entity)) {

            /* SrcMimGport */
            BCM_FIELD_QSET_ADD(fg->qset, _bcmFieldQualifySvpValid);
            fsm_ptr->rv = (BCM_E_NONE);
            fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_QSET_ALTERNATE;

        } else if ((_BCM_FIELD_STAGE_INGRESS == fg->stage_id) &&
            BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifySrcMplsGport) &&
            !BCM_FIELD_QSET_TEST(fg->qset, _bcmFieldQualifySvpValid) &&
            (1 == ingress_entity)) {

            /* SrcMplsGport */
            BCM_FIELD_QSET_ADD(fg->qset, _bcmFieldQualifySvpValid);
            fsm_ptr->rv = (BCM_E_NONE);
            fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_QSET_ALTERNATE;
        } else 
#endif /* !BCM_TRIUMPH2_SUPPORT */
        {
            /* Insert group into units group list. */
            if (BCM_SUCCESS(fsm_ptr->rv)) { 
                fsm_ptr->rv = _field_group_linked_list_insert(unit, fsm_ptr);
            }

            /* Success proceed to slice allocation. */
            if (BCM_SUCCESS(fsm_ptr->rv)) {
                fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SLICE_ALLOCATE;
            } else {
                fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
            }
        }
    }
    
    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET;

    return _field_group_add(unit, fsm_ptr);
}


/*
 * Function: 
 *     _field_group_add_qset_alternate
 * Purpose:
 *     Update application requested qset with equivalent one 
 *     which might allow to select F1, F2 Fn  select codes.
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_qset_alternate(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    /* Set current state to be previous state. */
    fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state; 

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
    if ((SOC_IS_FIREBOLT2(unit) || SOC_IS_RAVEN(unit) || SOC_IS_HAWKEYE(unit))
        && (BCM_FIELD_QSET_TEST(fsm_ptr->fg->qset, bcmFieldQualifyTtl))) {

        BCM_FIELD_QSET_REMOVE(fsm_ptr->fg->qset, bcmFieldQualifyTtl);
        if (SOC_IS_FIREBOLT2(unit)) {
            fsm_ptr->flags |= _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY; 
        }

        /* Proceed to a second attempt of select codes selection. */
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET;
    } else 
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAPTOR_SUPPORT */
#ifdef BCM_TRIUMPH2_SUPPORT
    if (soc_feature(unit, soc_feature_mim)) {
        /* Proceed to a second attempt of select codes selection. */
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET;
    } else if (BCM_FIELD_QSET_TEST(fsm_ptr->fg->qset, bcmFieldQualifySrcMplsGport)) {
        /* Proceed to a second attempt of select codes selection. */
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET;
    } else
#endif
    {
        fsm_ptr->rv = (BCM_E_RESOURCE);
        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
    }
    return _field_group_add(unit, fsm_ptr);
}

/*
 * Function: 
 *     _field_group_add_end
 * Purpose:
 *     Group add state machine last /clean up state.
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_add_end(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    if (BCM_FAILURE(fsm_ptr->rv)) {
        _field_group_deinit(unit, fsm_ptr->fg);
    }
    return (fsm_ptr->rv);

}

/*
 * Function: _field_group_add
 *     
 * Purpose:
 *     Create a field processor group 
 * Parameters:
 *     unit     - (IN)     BCM device number.
 *     fsm_ptr  - (IN/OUT) State machine tracking structure. 
 * Returns:
 *     BCM_E_XXX.
 */
STATIC int
_field_group_add(int unit, _field_group_add_fsm_t *fsm_ptr)
{
    int rv;             /* Operation return status.   */
                        /* Group add fsm state names. */
#if defined(BROADCOM_DEBUG)
    static char *_bcm_fp_group_add_state[bcmFieldQualifyCount] = \
        _BCM_FP_GROUP_ADD_STATE_STRINGS;
#endif /* BROADCOM_DEBUG */

    /* Input parameters check. */
    if (NULL == fsm_ptr) {
        return (BCM_E_PARAM);
    }

    rv = (BCM_E_NONE);

#if defined(BROADCOM_DEBUG)
    FP_VVERB(("FP(unit %d) vverb: group add: state (%s) state_prev (%s)  status (%d).\n", 
              unit, 
              _bcm_fp_group_add_state[fsm_ptr->fsm_state],   
              _bcm_fp_group_add_state[fsm_ptr->fsm_state_prev], 
              fsm_ptr->rv));
#endif /* BROADCOM_DEBUG */

    /* Run through group creation states. */
    switch (fsm_ptr->fsm_state) {
      case _BCM_FP_GROUP_ADD_STATE_START:
          rv = _field_group_add_initialize(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_ALLOC:
          rv = _field_group_add_alloc(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_QSET_UPDATE:
          rv = _field_group_add_qset_update(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET:
          rv = _field_group_add_sel_codes_get(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_QSET_ALTERNATE:
          rv = _field_group_add_qset_alternate(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_SLICE_ALLOCATE:
          rv = _field_group_add_slice_allocate(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_CAM_COMPRESS: 
          rv = _field_group_add_cam_compress(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_HW_QUAL_LIST_GET:
          rv = _field_group_add_hw_qual_list_get(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_UDF_UPDATE:
          rv = _field_group_add_udf_update(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_ADJUST_VIRTUAL_MAP:
          rv = _field_group_add_adjust_virtual_map(unit, fsm_ptr);
          break;

      case _BCM_FP_GROUP_ADD_STATE_END:
          rv = _field_group_add_end(unit, fsm_ptr);
          break;
     
    }
    return (rv);
}

/*
 * Function:
 *     _field_entries_free_get
 *
 * Purpose:
 *     Return the number of free entries in a slice.
 *
 * Parameters:
 *     unit        - (IN) BCM device number.
 *     fs          - (IN) Slice to count free entries in.
 *     fg          - (IN) Group (for checking the INTRASLICE-DW flag)
 *     free_cnt  - (OUT)Count of unused entries. 
 *
 * Returns:
 *     BCM_E_XXX
 *
 * Notes:
 *     Assumes all groups in a slice have the same mode (regular/INTRASLICE-DW)
 */
STATIC int 
_field_entries_free_get(int unit, _field_slice_t *fs, 
                        _field_group_t *fg, int *free_cnt)
{
    /* Input parameters check. */ 
    if ((NULL == fs) || (NULL == free_cnt)) {
        return (BCM_E_PARAM);
    }

    /* Initialization check. */
    FIELD_IS_INIT(unit);

    *free_cnt = fs->free_count;
    return (BCM_E_NONE);
}

/* 
 * Function:
 *     _field_counter_free_get
 *
 * Purpose:
 *     Report the number of unused counter pairs in a slice.
 *
 * Parameters:
 *     stage_fc     - (IN) Stage field control structure.
 *     fs           - (IN) Slice to count free counters in.
 *
 * Returns:
 *     Number of unused counters in slice.
 */
STATIC int 
_field_counter_free_get(const _field_stage_t *stage_fc,
                        const _field_slice_t *fs)
{
    int                 counter;
    int                 free_count = 0;

    /* Input parameters check. */
    if ((NULL == fs) || (NULL == stage_fc)) {
        return (BCM_E_PARAM);
    }

    if (fs->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        return fs->free_count;
    }
    
    /* Count unused counters. */ 
    for (counter = 0; counter < fs->counters_count; counter++) {
        if (0 == _FP_COUNTER_BMP_TEST(fs->counter_bmp, counter)) {
            free_count++;
        }
    }
    return free_count;
}

/* 
 * Function:
 *     _field_meter_free_get
 *
 * Purpose:
 *     Fill in the values of a group status struct.
 *
 * Parameters:
 *     stage_fc    - (IN) Stage field control structure.
 *     fs          - (IN) Slice to count free counters in.
 *
 * Returns:
 *     Number of unused meters in slice.
 */
STATIC int
_field_meter_free_get(const _field_stage_t *stage_fc,
                      const _field_slice_t *fs)
{
    int                 meter;
    int                 numb_meters = 0;

    /* Input parameters check. */
    if ((NULL == fs) || (NULL == stage_fc)) {
        return (BCM_E_PARAM);
    }

    if (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS) {
        int i;
        for (i = 0; i < stage_fc->num_meter_pools; i++) {
            numb_meters += stage_fc->meter_pool[i]->free_meters;
        }
        return numb_meters;
    }

    for (meter = 0; meter < fs->meters_count; meter++) {
        if (_FP_METER_BMP_TEST(fs->meter_bmp, meter)) {
            numb_meters++;
        }
    }
    return  fs->meters_count - numb_meters;
}


/*
 * Function:
 *     _field_udf_usecount_update
 * 
 * Purpose:
 *     Increment the use-counts of any new UDFs.
 *
 * Parameters:
 *     udf      - Unit's control array of UDFs
 *     qset_old - Previous Qset
 *     qset_new - New Qset 
 *
 * Returns:
 *     nothing
 */
STATIC void
_field_udf_usecount_update(_field_udf_t *udf,
                           bcm_field_qset_t *qset_old,
                           bcm_field_qset_t *qset_new)
{
    int                  idx_new;

    /* For all UDFs in new Qset. */
    for (idx_new = 0; idx_new < BCM_FIELD_USER_NUM_UDFS; idx_new++) {
        if (!SHR_BITGET(qset_new->udf_map, idx_new)) {
            continue;
        }

        /* If UDF is in new Qset but not in old Qset, increment use-count. */
        if (!SHR_BITGET(qset_old->udf_map, idx_new)) {
            udf[idx_new].use_count++;
        }
    }
}

/*
 * Function: _field_fb_entries_enable_set
 *    
 * Purpose:
 *     Enable/disable the lookup of entries of a group
 *
 * Parameters:
 *     unit   - BCM device number
 *     fg     - Group the entry belongs to
 *     fs     - Slice the entry is present in
 *     enable - lookup enable!=0/disable==0 state of group
 *
 * Returns:
 *     BCM_E_NONE      - Success
 *     BCM_E_XXX       - BCM error codes
 *
 * Note:
 *     For Intraslice-dw (FB2), we run over entries in both half's.
 *     
 *     A group may be spanning multiple slices 
 *         (due to group autoexpansion)
 */
int 
_field_fb_entries_enable_set(int unit, _field_group_t *fg, 
                              _field_slice_t *fs, int enable)
{
    _field_stage_t *stage_fc;
    soc_mem_t mem = INVALIDm;
    uint32  e[SOC_MAX_MEM_FIELD_WORDS];
    int index, i;

    /* External stage entries are always enabled */
    if (_BCM_FIELD_STAGE_EXTERNAL == fg->stage_id) {
        return (BCM_E_NONE);
    }
    
    BCM_IF_ERROR_RETURN
        (_field_stage_control_get(unit, fg->stage_id, &stage_fc));

    if (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
        mem = FP_TCAMm;
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    } else if (soc_feature(unit, soc_feature_field_multi_stage)) {
        if (_BCM_FIELD_STAGE_LOOKUP  == stage_fc->stage_id) {
            mem = VFP_TCAMm; 
        } else if (_BCM_FIELD_STAGE_EGRESS  == stage_fc->stage_id) { 
            mem = EFP_TCAMm;
        } else {
            return (BCM_E_INTERNAL);
        }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    } else {
        return BCM_E_INTERNAL;
    }

    while (fs->next != NULL) {
        fs = fs->next;
    }

    while (fs != NULL) {
        for (i = fs->entry_count - 1; i >= 0; i--) {
            if (fs->entries[i] != NULL) {
                if (fs->entries[i]->group->gid == fg->gid) {
                    BCM_IF_ERROR_RETURN(
                                        _bcm_field_entry_tcam_idx_get(unit, fs->entries[i], &index));
                    /* Read tcam entry from index. */
                    SOC_IF_ERROR_RETURN
                        (soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, e));

                    /* Set the VALIDf bits appropriately */
                    if (enable) {
                        if (fs->entries[i]->flags & _FP_ENTRY_INSTALLED) {
                            soc_mem_field32_set(unit, mem, e, VALIDf, 3);
                        } else {
                            soc_mem_field32_set(unit, mem, e, VALIDf, 0);
                        }
                    } else {
                        soc_mem_field32_set(unit, mem, e, VALIDf, 2);
                    }
            
                    /* Write back the TCAM entry */
                    SOC_IF_ERROR_RETURN
                        (soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, e));
                }
            }
        }
        fs = fs->prev;
    }

    if (enable) {
        fg->flags |= _FP_GROUP_LOOKUP_ENABLED;
    } else {
        fg->flags &= ~_FP_GROUP_LOOKUP_ENABLED;
    }
 
    return BCM_E_NONE;
}

/*
 * Function: _field_range_flags_check
 *    
 * Purpose:
 *     Sanity check on range flags. 
 *
 * Parameters:
 *     unit   - (IN) BCM device number.
 *     flags  - (IN) One or more of BCM_FIELD_RANGE_* flags.
 *
 * Returns:
 *     BCM_E_XXX  - Flags are valid & supported.
 */
STATIC int
_field_range_flags_check(int unit, uint32 flags)
{
    int   cntr;                 /* Range types counter.  */

    /* ESW family of devices do not support range check in lookup stage */
    if (flags & BCM_FIELD_RANGE_LOOKUP) {
        return (BCM_E_UNAVAIL);
    }

    /* Make sure only one range was selected. */
    cntr = 0;
    if (flags & BCM_FIELD_RANGE_SRCPORT) {
        cntr++;
    }
    if (flags & BCM_FIELD_RANGE_DSTPORT) {
        cntr++;
    }
    if (flags & BCM_FIELD_RANGE_OUTER_VLAN) {
        cntr++;
    }
    if (flags & BCM_FIELD_RANGE_PACKET_LENGTH) {
        cntr++;
    }
    if (cntr > 1) {
        return (BCM_E_PARAM);
    }

    /* Outer vlan & packet length ranges supported by trx devices only.*/
    if ((flags & BCM_FIELD_RANGE_OUTER_VLAN)  || 
        (flags & BCM_FIELD_RANGE_PACKET_LENGTH)) {
        if (0 == SOC_IS_TRX(unit)) {
            return (BCM_E_UNAVAIL);
        }
    }

    /* Range TCP/UDP/Invert supported on 5660x devices only. */
    if (flags & (BCM_FIELD_RANGE_TCP | 
                 BCM_FIELD_RANGE_UDP |
                 BCM_FIELD_RANGE_INVERT)) { 
        if(0 == (SOC_IS_EASYRIDER(unit))) {
            return (BCM_E_UNAVAIL);
        }
    }
    return (BCM_E_NONE);
}


/*
 * Function: _field_range_create
 *    
 * Purpose:
 *     Create field range object.
 *
 * Parameters:
 *     unit   - (IN) BCM device number.
 *
 * Returns:
 *     BCM_E_XXX 
 */
STATIC int
_field_range_create(int unit, bcm_field_range_t *range,
                    uint32 flags, bcm_l4_port_t min,
                    bcm_l4_port_t max, bcm_if_group_t group)
{
    _field_stage_t      *stage_fc;
    int                 rv;

    if (flags & BCM_FIELD_RANGE_EXTERNAL) {
        BCM_IF_ERROR_RETURN
            (_field_stage_control_get(unit, _BCM_FIELD_STAGE_EXTERNAL, 
                                      &stage_fc));
    } else {
        BCM_IF_ERROR_RETURN
            (_field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, 
                                      &stage_fc));
    }

    for (;;) {
        if (group == -1) {
            rv = bcm_esw_field_range_create_id(unit, stage_fc->range_id,
                                               flags, min, max);
        } else {
            rv = bcm_esw_field_range_group_create_id(unit, stage_fc->range_id,
                                                     flags, min, max, group);
        }

        if (rv != BCM_E_EXISTS) {
            break;
        }

        if (++stage_fc->range_id == 0) {
            stage_fc->range_id = 1;
        }
    }

    if (BCM_SUCCESS(rv)) {
        *range = stage_fc->range_id;

        if (++stage_fc->range_id == 0) {
            stage_fc->range_id = 1;
        }
    }
    return rv;
}

/*
 * Function:
 *     _field_fb_er_range_check_set
 * Purpose:
 *     Write the group's range checking parameters into the FP_RANGE_CHECK
 *     memory.
 * Parameters:
 *     unit   - BCM unit
 *     range  - Range HW index
 *     flags  - One of more of the BCM_FIELD_RANGE_* flags
 *     enable - TRUE or FALSE
 *     min    - Lower bounds of port range to be checked
 *     max    - Upper bounds of port range to be checked
 * Returns:
 *     BCM_E_NONE
 *     BCM_E_PARAM - Unrecognized flag.
 * Notes:
 *    Calling function should have unit's lock.
 */
STATIC int
_field_fb_er_range_check_set(int unit, int range, uint32 flags, int enable,
                             bcm_l4_port_t min, bcm_l4_port_t max)
{
    fp_range_check_entry_t  tbl_entry;
    uint32                  src_chk = 0;

    assert(soc_mem_index_valid(unit, FP_RANGE_CHECKm, range));

    if (enable) {
        switch (flags & (BCM_FIELD_RANGE_SRCPORT | BCM_FIELD_RANGE_DSTPORT)) {
        case BCM_FIELD_RANGE_SRCPORT:
            src_chk = 1;
            break;
        case BCM_FIELD_RANGE_DSTPORT:
            break;
        default:
            FP_ERR(("FP(unit %d) Error: unsupported flags %#x\n", unit, flags));
            return (BCM_E_PARAM);
        }
    }

    /* read/modify/write range check memory */
    SOC_IF_ERROR_RETURN(READ_FP_RANGE_CHECKm(unit, MEM_BLOCK_ANY, 
                                             range, &tbl_entry));

    soc_FP_RANGE_CHECKm_field32_set(unit, &tbl_entry, 
                                    SOURCE_DESTINATION_SELECTf, src_chk);
    soc_FP_RANGE_CHECKm_field32_set(unit, &tbl_entry, ENABLEf, enable);
    soc_FP_RANGE_CHECKm_field32_set(unit, &tbl_entry, LOWER_BOUNDSf, min);
    soc_FP_RANGE_CHECKm_field32_set(unit, &tbl_entry, UPPER_BOUNDSf, max);

    SOC_IF_ERROR_RETURN(WRITE_FP_RANGE_CHECKm(unit, MEM_BLOCK_ALL, 
                                              range, &tbl_entry));
    
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_trans_flags_to_index
 * Purpose:
 *     Translate the client flags into a 7-bit FP_UDF_OFFSETm index.
 * Parameters:
 *     flags   - Client specified flags.
 *     tbl_idx - (OUT) index into UDF_OFFSET table
 * Returns:
 *     BCM_E_RESOURCE Client's flags won't work on this unit.
 *     BCM_E_NONE
 * Notes:
 */
int
_field_trans_flags_to_index(int unit, int flags, uint8 *tbl_idx)
{
    uint32              flag_mask;

    flag_mask = BCM_FIELD_USER_VLAN_MASK | BCM_FIELD_USER_L2_MASK |
      BCM_FIELD_USER_IP_MASK | BCM_FIELD_USER_OPTION_ADJUST |
      BCM_FIELD_USER_HIGIG;

#if defined(BCM_RAPTOR_SUPPORT)
    if (SOC_IS_RAPTOR(unit) || SOC_IS_RAVEN(unit)) {
        flag_mask = BCM_FIELD_USER_VLAN_MASK | BCM_FIELD_USER_L2_MASK |
                    BCM_FIELD_USER_IP_MASK | BCM_FIELD_USER_OPTION_ADJUST |
                    BCM_FIELD_USER_HIGIG2;
    } else if (SOC_IS_HAWKEYE(unit)) {
        flag_mask = BCM_FIELD_USER_VLAN_MASK | BCM_FIELD_USER_L2_MASK |
                    BCM_FIELD_USER_IP_MASK | BCM_FIELD_USER_OPTION_ADJUST;
    }
#endif /* BCM_RAPTOR_SUPPORT */

    if (flags & ~(flag_mask)) {
        FP_ERR(("FP(unit %d) Error: Invalid Flags=0x%x, flag_mask=0x%x\n", unit, flags,
                flag_mask));
        return (BCM_E_PARAM);
    }

    *tbl_idx = 0u; /* clear table index bits */

    /* Translate VLAN flag bits to index bits [6:5] */
    flag_mask = BCM_FIELD_USER_VLAN_MASK;
    if ((flags & flag_mask) == BCM_FIELD_USER_VLAN_NOTAG) { /* */
        *tbl_idx |=  0x0 << 5; /* 2'b00 */
    }
    else if ((flags & flag_mask) == BCM_FIELD_USER_VLAN_ONETAG) { 
        *tbl_idx |=  0x1 << 5; /* 2'b01 */
    }
    else if ((flags & flag_mask) == BCM_FIELD_USER_VLAN_TWOTAG) { /* */
        *tbl_idx |=  0x2 << 5; /* 2'b10 */
    } else {
        FP_ERR(("FP(unit %d) Error: Flags 0x%x needs a Tag flag.\n", unit, flags));
        return (BCM_E_UNAVAIL);
    }

    /* Translate L2 flag bits to index bits [4:3] */
    flag_mask = BCM_FIELD_USER_L2_MASK;
    if ((flags & flag_mask) == BCM_FIELD_USER_L2_ETHERNET2) { /* Ethernet II */
        *tbl_idx |=  0x0 << 3; /* 2'b00 */
    }
    else if ((flags & flag_mask) == BCM_FIELD_USER_L2_SNAP) { /* 802.3 SNAP  */
        *tbl_idx |=  0x1 << 3; /* 2'b01 */
    }
    else if ((flags & flag_mask) == BCM_FIELD_USER_L2_LLC)  { /* 802.3 LLC   */
        *tbl_idx |=  0x2 << 3; /* 2'b10 */
    }
    else {
        FP_ERR(("FP(unit %d) Error: Flags 0x%x needs L2 Format flag.\n", unit, flags));
        return (BCM_E_UNAVAIL);
    }

    /* Translate IP flag bits to index bits [2:0] */
    flag_mask = BCM_FIELD_USER_IP_MASK;
    if (SOC_IS_EASYRIDER(unit)) {
        if ((flags & flag_mask) == BCM_FIELD_USER_IP4_HDR_ONLY) {
            *tbl_idx |=  0x0; /* 3'b000 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP6_HDR_ONLY) {
            *tbl_idx |=  0x1; /* 3'b001 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP4_OVER_IP4) {
            *tbl_idx |=  0x2; /* 3'b010 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP6_OVER_IP4) {
            *tbl_idx |=  0x3; /* 3'b011 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP_NOTUSED) {
            *tbl_idx |=  0x4; /* 3'b100 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP6_FRAGMENT) {
            *tbl_idx |=  0x5; /* 3'b101 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP6_FRAGMENT_OVER_IP4) {/* No L3 Hdr */
            *tbl_idx |=  0x6; /* 3'b110 */
        }
        else {
            FP_ERR(("FP(unit %d) Error: Flags 0x%x needs IP Header Format flag.\n", unit, flags));
            return (BCM_E_UNAVAIL);
        }
    } else {
        if ((flags & flag_mask) == BCM_FIELD_USER_IP4_HDR_ONLY) {
            *tbl_idx |=  0x0; /* 3'b000 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP6_HDR_ONLY) {
            *tbl_idx |=  0x1; /* 3'b001 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP4_OVER_IP4) {
            *tbl_idx |=  0x2; /* 3'b010 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP6_OVER_IP4) {
            *tbl_idx |=  0x3; /* 3'b011 */
        }
        else if ((flags & flag_mask) == BCM_FIELD_USER_IP_NOTUSED) {/* No L3 Hdr */
            *tbl_idx |=  0x4; /* 3'b100 */
        }
        else {
            FP_ERR(("FP(unit %d) Error: Flags 0x%x needs IP Header Format flag.\n", unit, flags));
            return (BCM_E_UNAVAIL);
        }
    }

#ifdef BCM_FIREBOLT_SUPPORT
    if (SOC_IS_FBX(unit)) {
        assert(*tbl_idx <= soc_mem_index_max(unit, FP_UDF_OFFSETm));
    }
#endif /* BCM_FIREBOLT_SUPPORT */

#ifdef BCM_EASYRIDER_SUPPORT
    if (SOC_IS_EASYRIDER(unit)) {
        assert(*tbl_idx <= soc_mem_index_max(unit, UDF_OFFSETm));
    }
#endif /* BCM_EASYRIDER_SUPPORT */

    return (BCM_E_NONE);
}


/*
 * Function: _field_find_empty_slice
 *
 * Purpose:
 *     Get a new slice for an existing group if available.
 *     Used for auto-expansion of groups
 *     Currently: supported in Raptor, Firebolt2.
 *
 * Parameters:
 *     unit  - BCM device number
 *     fg - field group
 *     fs_ptr - _field_slice_t for the PRIMARY if there is one available.
 *
 * Returns:
 *     BCM_E_xxx
 *
 * Notes:
 *     Need to change the array size (16) for devices which support
 *     more slices, and correspondingly change the map arrays in
 *     bcm_int/esw/field.h
 */
STATIC int 
_field_find_empty_slice(int unit, _field_group_t *fg, _field_slice_t **fs_ptr)
{
    _field_control_t *fc;          /* Field control structure. */ 
    _field_stage_t   *stage_fc;    /* Field stage control.     */
    _field_slice_t   *fs;          /* Field slice pointer.     */
    uint8 slice_number;            /* Slice iterator.          */
    int parts_count;               /* Number of entry parts.   */
    uint16 entry_flags;            /* Field entry part flags.  */
    int rv;                        /* Operation return status. */
    int part_index;
    int slice_index;
    uint8 old_physical_slice;      /* Last slice in group.     */
    uint8 new_physical_slice;      /* Allocated slice.         */
    bcm_port_config_t  port_config;/* Device port config.      */

    /* Get field control structure. */
    rv = _field_control_get(unit, &fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Read device port configuration. */ 
    BCM_IF_ERROR_RETURN(bcm_esw_port_config_get(unit, &port_config));

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    if (0 == (stage_fc->flags & _FP_STAGE_AUTO_EXPANSION)) {
        return (BCM_E_RESOURCE);
    }

    fs = &fg->slices[0];
    while (fs->next != NULL) {
        fs = fs->next;
    }
    old_physical_slice = fs->slice_number;

    /* 
     * Find an empty slice 
     * Validate the ports and mode 
     */
    for (slice_index = 0; slice_index < stage_fc->tcam_slices; slice_index++) {
        rv = _field_group_ports_validate(unit, stage_fc, slice_index, 
                                         fg->flags, port_config.all);
        if (BCM_SUCCESS(rv)) {
            break;
        }
    }

    if (slice_index == stage_fc->tcam_slices) {
        /* No free slice; attempt to compress existing auto expanded  groups. */
        rv = _field_stage_groups_compress(unit, fc, stage_fc);
        BCM_IF_ERROR_RETURN(rv);

        /* Retry slice allocation. */
        for (slice_index = 0; slice_index < stage_fc->tcam_slices; slice_index++) {
            rv = _field_group_ports_validate(unit, stage_fc, slice_index, 
                                             fg->flags, port_config.all);
            if (BCM_SUCCESS(rv)) {
                break;
            }
        }
    }

    if (slice_index == stage_fc->tcam_slices)
    {
        /* No free slice */

        return (BCM_E_RESOURCE);
    }

    new_physical_slice = slice_index;

    /* Remove original group from the map. */
    rv = _field_group_vmap_delete(unit, stage_fc, fg, FALSE);
    BCM_IF_ERROR_RETURN(rv);

    /* Get number of entry parts for the group. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);


    /* Set up the new physical slice parameters in Software */
    for(part_index = parts_count - 1; part_index >= 0; part_index--) {
        /* Get entry flags. */
        rv = _bcm_field_tcam_part_to_entry_flags(part_index, fg->flags, &entry_flags);
        BCM_IF_ERROR_RETURN(rv);

        /* Get slice id for entry part */
        rv = _bcm_field_tcam_part_to_slice_number(part_index, fg->flags, &slice_number);
        BCM_IF_ERROR_RETURN(rv);

        /* Get slice pointer. */
        fs = stage_fc->slices + new_physical_slice + slice_number;

        /* Enable slice. */
        if (0 == (entry_flags & _FP_ENTRY_SECOND_HALF)) {
#ifdef BCM_FIREBOLT_SUPPORT
            if (stage_fc->flags & _FP_STAGE_SLICE_ENABLE) { 
                rv = _field_fb_slice_enable_set(unit, fg, fs->slice_number, 1);
                BCM_IF_ERROR_RETURN(rv);
            }
#endif /* BCM_FIREBOLT_SUPPORT */
            /* Set per slice configuration &  number of free entries in the slice.*/
            fs->free_count = fs->entry_count;
            if (fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
                fs->free_count >>= 1;
            }
            /* Set group flags in in slice.*/ 
            fs->group_flags = fg->flags & _FP_GROUP_STATUS_MASK;

            /* Add slice to slices linked list . */
            stage_fc->slices[old_physical_slice + slice_number].next = fs;
            fs->prev = &stage_fc->slices[old_physical_slice + slice_number];
            BCM_PBMP_OR(fs->pbmp, fg->pbmp);
        }

        rv = fc->functions.fp_selcodes_install(unit, fg, 
                                               new_physical_slice + slice_number,
                                               fs->pbmp, part_index);
        BCM_IF_ERROR_RETURN(rv);

        /* Set source class selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[part_index].src_class_sel) {
            fs->src_class_sel = fg->sel_codes[part_index].src_class_sel;
        }
        /* Set destination class selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[part_index].dst_class_sel) {
            fs->dst_class_sel = fg->sel_codes[part_index].dst_class_sel;
        }
        /* Set interface class selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[part_index].intf_class_sel) {
            fs->intf_class_sel = fg->sel_codes[part_index].intf_class_sel;
        }
        /* Set loopback type/tunnel type selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[part_index].loopback_type_sel) {
            fs->loopback_type_sel = fg->sel_codes[part_index].loopback_type_sel;
        }
        /* Set ingress entity type selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[part_index].ingress_entity_sel) {
            fs->ingress_entity_sel = fg->sel_codes[part_index].ingress_entity_sel;
        }
        /* Set src entity type selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[part_index].src_entity_sel) {
            fs->src_entity_sel = fg->sel_codes[part_index].src_entity_sel;
        }
        /* Set destination forwarding entity type selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[part_index].dst_fwd_entity_sel) {
            fs->dst_fwd_entity_sel = fg->sel_codes[part_index].dst_fwd_entity_sel;
        }

        /* Set destination forwarding field selection. */
        if (_FP_SELCODE_DONT_CARE != fg->sel_codes[part_index].fwd_field_sel) {
            fs->fwd_field_sel = fg->sel_codes[part_index].fwd_field_sel;
        }

        /* Set intraslice double wide key selection. */
        if (fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            if ((_FP_SELCODE_DONT_CARE != fg->sel_codes[part_index].fpf2) &&
                ((part_index == _FP_INTRA_SLICE_PART_1) ||
                 (part_index == _FP_INTRA_SLICE_PART_3))) {
                fs->doublewide_key_select = fg->sel_codes[part_index].fpf2;
            }
        }
    }

    /* Reinstall group virtual map . */
    BCM_IF_ERROR_RETURN (_field_group_vmap_add(unit, stage_fc, fg));

    *fs_ptr = stage_fc->slices + new_physical_slice;
    return (BCM_E_NONE);
}



/*
 * Function: _field_group_slice_entry_reserve
 *
 * Purpose:
 *      Find a slice attached to a group which has a room
 *      to insert a new entry.
 * Parameters:
 *     unit  - (IN) BCM device number.
 *     fg    - (IN/OUT) Field group.
 *     fs    - (OUT) Slice pointer or NULL. 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_slice_entry_reserve(int unit, _field_group_t *fg,
                                 _field_slice_t **fs)
{
    _field_slice_t  *slice;        /* Slice iteration count.           */
    int             free_entry_cnt;/* Free entries in slice count.     */

    /* Input parameters check. */
    if ((NULL == fg) || (NULL == fs)) {
        return (BCM_E_PARAM);
    }

    /* Find an empty spot in one of the groups slices.  */
    slice = &fg->slices[0];
    while (slice->next != NULL) {
        slice = slice->next; /* Start from the last slice */
    }

    while (slice != NULL) {
        BCM_IF_ERROR_RETURN
            (_field_entries_free_get(unit, slice, fg, &free_entry_cnt));
        if (free_entry_cnt) {
            break;
        }
        slice = slice->prev;
    }

    /* 
     * If there is no room in existing group slices try to allocate a new one.
     * Find a feasible empty slice for auto-expand 
     * Set these slices in the same virtual group
     */
    if (slice == NULL) {
        BCM_IF_ERROR_RETURN(_field_find_empty_slice(unit, fg, &slice));

        BCM_IF_ERROR_RETURN
            (_field_entries_free_get(unit, slice, fg, &free_entry_cnt));

        if (0 == free_entry_cnt) {
            FP_ERR(("FP(unit %d) Error: No entries free in slice.\n", unit));
            return (BCM_E_RESOURCE);
        }
    }
    *fs = slice;
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_entry_actions_free
 * Purpose:
 *     Free and deinitialize field entry actions linked list
 * Parameters:
 *     f_ent       - (IN/OUT) Field entry with actions.
 *     color_only  - (IN) Color based actions only.
 *     
 * Returns:
 *     BCM_E_MEMORY - allocation failure
 *     BCM_E_NONE   - Success
 */
STATIC int
_field_entry_actions_free (_field_entry_t *f_ent, int color_only) 
{
    _field_action_t *fa;        /* Action structure pointer. */
    _field_action_t *fa_prev;   /* Action structure pointer. */

    /* Input parameters check.*/
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    fa_prev = fa = f_ent->actions;

    /* Free actions from the entry. */
    while (fa != NULL) {
        if (color_only && (!_FP_ACTION_IS_COLOR_BASED(fa->action))) {
            fa_prev = fa;
            fa = fa->next;
            continue;
        }

        /* Head entry deletion. */
        if (fa == f_ent->actions) {
            f_ent->actions = fa->next;     
            sal_free(fa);
            fa_prev = fa = f_ent->actions;
        } else {
            /* Middle/Tail entry deletion. */
            fa_prev->next = fa->next;
            sal_free(fa);
            fa = fa_prev->next;
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_entry_phys_destroy
 *
 * Purpose:
 *     Destroy a physical entry from a slice. Note that this does not remove
 *     the entry from the hardware.
 *
 * Parameters:
 *     unit      - BCM device number
 *     fs        - slice that entry resides in
 *     entry     - Entry ID to remove
 *
 * Returns:
 *     BCM_E_NONE - Success
 */   
STATIC int
_field_entry_phys_destroy (int unit, _field_entry_t *f_ent)
{
    _field_control_t *fc;         /* Field control structure.        */
    _field_stage_t   *stage_fc;   /* Stage field control.            */
    _field_group_t   *fg;         /* Field group structure.          */
    _field_slice_t   *fs;         /* Field slice structure.          */
    int              parts_count; /* Entry parts count.              */
    uint8            slice_number;/* Field entry part slice number.  */
    int              idx;         /* Entry parts iterator.           */    
    int              rv;          /* Operation return status.        */

    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    fs = f_ent->fs;
    fg = f_ent->group;

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, fs->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Get number of entry parts we have to read. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    for (idx = 0; idx < parts_count; idx++) {
        /* Destroy all actions from entry. */
        rv = _field_entry_actions_free (f_ent + idx, FALSE);
        BCM_IF_ERROR_RETURN(rv);

        /* Free tcam image. */
        if(NULL != f_ent[idx].tcam.key) {
            sal_free(f_ent[idx].tcam.key);
        }
        if(NULL != f_ent[idx].tcam.mask) {
            sal_free(f_ent[idx].tcam.mask);
        }
        if(NULL != f_ent[idx].tcam.key_hw) {
            sal_free(f_ent[idx].tcam.key_hw);
        }
        if(NULL != f_ent[idx].tcam.mask_hw) {
            sal_free(f_ent[idx].tcam.mask_hw);
        }
        if(NULL != f_ent[idx].extra_tcam.key) {
            sal_free(f_ent[idx].extra_tcam.key);
        }
        if(NULL != f_ent[idx].extra_tcam.mask) {
            sal_free(f_ent[idx].extra_tcam.mask);
        }
        if(NULL != f_ent[idx].extra_tcam.key_hw) {
            sal_free(f_ent[idx].extra_tcam.key_hw);
        }
        if(NULL != f_ent[idx].extra_tcam.mask_hw) {
            sal_free(f_ent[idx].extra_tcam.mask_hw);
        }
        /* Get slice id for entry part */
        rv = _bcm_field_tcam_part_to_slice_number(idx, fg->flags, &slice_number);
        BCM_IF_ERROR_RETURN(rv);

        /* Remove entry pointer from the slice. */
        if (stage_fc->stage_id != _BCM_FIELD_STAGE_EXTERNAL) {
            fs[slice_number].entries[f_ent[idx].slice_idx] = NULL;
        }

        /* Increment slice unused entry count. */
        if (0 == (f_ent[idx].flags & _FP_ENTRY_SECOND_HALF)) {
            fs[slice_number].free_count++;
        }
    }

    /* Remove the entry from group entry array. */
    rv = _field_group_entry_delete(unit, fg,  f_ent);
    if (BCM_FAILURE(rv)) {
        sal_free(f_ent);
        return (rv);
    }

    /* Free the entry */
    sal_free(f_ent);

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_entry_part_tcam_idx_get
 *
 * Purpose:
 *     Given primary entry slice/idx calculate 
 *     secondary/tertiary/second half slice/index.
 *
 * Parameters:
 *     unit    - (IN) BCM device number.  
 *     f_ent   - (IN) Field entry pointer.
 *     idx_pri - (IN) Primary entry tcam index.
 *     ent_part    - (IN) Entry part id.
 *     idx_out - (OUT) Entry part tcam index.
 * Returns
 *     BCM_E_XXX
 *
 */   
int
_bcm_field_entry_part_tcam_idx_get(int unit, _field_entry_t *f_ent,
                                   uint32 idx_pri, uint8 ent_part, 
                                   int *idx_out)
{
    uint8            slice_number = 0;/* Primary entry slice number.    */
    int              pri_slice = 0;   /* Primary entry slice number.    */
    int              pri_index = 0;   /* Primary entry in slice index.  */
    int              part_index;      /* Entry part slice index.        */
    _field_stage_t   *stage_fc;       /* Stage field control.           */
    _field_slice_t   *fs;             /* Field slice structure.         */
    _field_group_t   *fg;             /* Field group structure.         */
    int              rv;              /* Operation return status.       */

    /* Input parameters ceck. */ 
    if ((NULL == f_ent) || (NULL == idx_out)) {
        return (BCM_E_PARAM);
    }

    /* Primary entry index. */
    if (0 == ent_part) {
        *idx_out = idx_pri;
        return (BCM_E_NONE);
    }

    fg = f_ent->group;

    /* External tcam doesn't support wide entries. */
    if (_BCM_FIELD_STAGE_EXTERNAL == fg->stage_id) {
        return (BCM_E_INTERNAL);
    }

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Get primary part entry index & slice. */
    rv = _bcm_field_tcam_idx_to_slice_offset (unit, stage_fc, idx_pri, 
                                              &pri_slice, &pri_index);
    BCM_IF_ERROR_RETURN(rv);

    /* Get entry part slice number 0,1,2 */
    rv = _bcm_field_tcam_part_to_slice_number(ent_part, fg->flags, 
                                              &slice_number);
    BCM_IF_ERROR_RETURN(rv);

    /* Get slice description structure. */
    fs = stage_fc->slices + (pri_slice + slice_number); 

    if (f_ent[ent_part].flags &  _FP_ENTRY_SECOND_HALF) {
        part_index = pri_index + (fs->entry_count >> 1);
    } else {
        part_index = pri_index;
    }

    rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc,
                                             fs->slice_number, 
                                             part_index, idx_out);
    return (rv);
}

/*
 * Function:
 *     _field_entry_phys_create
 *
 * Purpose:
 *     Initialize a physical entry structure.
 *
 * Parameters:
 *     unit           - (IN) BCM device number.  
 *     stage_fc       - (IN) Stage field control structure.  
 *     entry          - (IN) Entry ID.
 *     prio           - (IN) Priority relative to other entries in group.
 *     fs             - (IN) Slice where entry resides.
 *     fg             - (IN) Entry's group.
 *     entry_p        - (OUT)Allocated & initialized entry.       
 *
 * Returns
 *     BCM_E_XXX
 *
 * Notes:
 *     Assumes that for wide-mode, the same index within the slice
 *     is assigned for the 2(3) slices.
 */   
STATIC int
_field_entry_phys_create(int unit, _field_stage_t *stage_fc, 
                         bcm_field_entry_t entry, int prio,
                         _field_slice_t *fs, _field_group_t *fg,
                         _field_entry_t **entry_p)
{
    _field_control_t    *fc;          /* Field control structure.         */
    int                 idx;          /* Slice entries iteration index.   */   
    int                 parts_count;  /* Number of entry parts.           */
    int                 part_index;   /* Entry parts iterator.            */
    int                 rv;           /* Operation return status.         */
    int                 mem_sz;       /* Memory allocation size.          */
    int                 slice_number = 0;/* Field entry part slice number.*/
    _field_entry_t      *f_ent = NULL;/* Field entry structure.           */
    int                 pri_tcam_idx; /* Primary entry tcam index.        */

    FP_VVERB(("FP(unit %d) vverb: BEGIN _field_entry_phys_create(entry=%d, prio=%d, gid=%d)\n", 
              unit, entry, prio, fg->gid));

    if ((NULL == fs) || (NULL == fg) || (NULL == entry_p)) {
        return (BCM_E_PARAM);
    }

    /* Check if free entries are available in the slice. */
    if (0 == fs->free_count) {
        return (BCM_E_RESOURCE);
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Get number of parts in field entry based on group flags. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Allocate and zero memory for field entry. */
    mem_sz = parts_count * sizeof (_field_entry_t);

    _FP_XGS3_ALLOC(f_ent, mem_sz, "field entry");
    if (f_ent == NULL) {
        FP_ERR(("FP(unit %d) Error: allocation failure for field_entry\n", unit));
        return (BCM_E_MEMORY);
    }

    /* 
     * In External TCAM, each slice has different number of entries
     *     Also, allocation happens only at Install time
     */
    if (fg->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        f_ent->slice_idx = -1;
    } else {
        /* Get index for primary entry. */
        for (idx = 0; idx < fs->entry_count; idx++) {
            if (NULL == fs->entries[idx]) {
                f_ent->slice_idx = idx;
                break;
            }
        }
        rv = _bcm_field_slice_offset_to_tcam_idx (unit, stage_fc,
                                                  fs->slice_number,
                                                  f_ent->slice_idx,
                                                  &pri_tcam_idx);
        if (BCM_FAILURE(rv)) {
            sal_free(f_ent);
            return (rv);
        }
    }

    for (idx = 0; idx < parts_count; idx++) {
        /* Fill in entry primitives. */
        f_ent[idx].eid          = entry;
        f_ent[idx].prio         = prio;
        f_ent[idx].group        = fg;

        /* Get entry part flags. */
        rv = _bcm_field_tcam_part_to_entry_flags(idx, fg->flags,
                                                 &f_ent[idx].flags);
        if (BCM_FAILURE(rv)) {
            sal_free(f_ent);
            return (rv);
        }

        /* Enable color independent actions based on field control. */
        if (fc->flags & _FP_COLOR_INDEPENDENT) {
            f_ent[idx].flags |= _FP_ENTRY_COLOR_INDEPENDENT;
        }

        /* Given primary entry tcam index calculate entry part tcam index. */
        if (idx && (_BCM_FIELD_STAGE_EXTERNAL != fg->stage_id)) {
            rv = _bcm_field_entry_part_tcam_idx_get(unit, f_ent, pri_tcam_idx,
                                                    idx, &part_index);
            if (BCM_FAILURE(rv)) {
                sal_free(f_ent);
                return (rv);
            }

            rv = _bcm_field_tcam_idx_to_slice_offset (unit, stage_fc,
                                                      part_index, &slice_number,
                                                      (int *)&f_ent[idx].slice_idx);
            if (BCM_FAILURE(rv)) {
                sal_free(f_ent);
                return (rv);
            }
            f_ent[idx].fs = stage_fc->slices + slice_number;
        } else {
            /* Set entry slice. */
            f_ent[idx].fs = fs;
        }

        if (0 == (f_ent[idx].flags & _FP_ENTRY_SECOND_HALF)) {
            /* Decrement slice free entry count for primary entries. */
            f_ent[idx].fs->free_count--;
        }

        /* Assign entry to a slice */
        if (fg->stage_id != _BCM_FIELD_STAGE_EXTERNAL) {
            f_ent[idx].fs->entries[f_ent[idx].slice_idx] = f_ent + idx;
        }

        /* Mark entry dirty. */
        f_ent[idx].flags |=  _FP_ENTRY_DIRTY;
    }

    /* Insert the entry into group entry array. */
    rv = _field_group_entry_add(unit, fg,  f_ent);
    if (BCM_FAILURE(rv)) {
        sal_free(f_ent);
        return (rv);
    }

    /* Return allocated/filled entry structure to the caller. */
    *entry_p = f_ent;
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_tcam_policy_external_reinstall
 *
 * Purpose:
 *     Re-Install POLICY_TABLE entry. This writes the
 *     actions to the hardware.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Entry to be installed.
 *
 * Returns:
 *     BCM_E_INTERNAL  - Memory Read failure
 *     BCM_E_UNAVAIL   - Device not supported
 *     BCM_E_NONE      - Success
 *
 * Notes:
 */
STATIC int
_field_tcam_policy_external_reinstall(int unit, _field_entry_t *f_ent)
{
    _field_control_t    *fc;         /* Field control structure.  */
    int                 rv;          /* Operation return status.  */

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* If not installed, and no qualifiers yet  
     *     i.e. installing empty entry for first time
     */
    if (0 == (f_ent->flags & _FP_ENTRY_INSTALLED)) {
        BCM_IF_ERROR_RETURN (_bcm_field_qual_tcam_key_mask_get(unit, f_ent));
    }

    /* Next copy S/W copy to H/W copy if required */
    if(NULL != f_ent->tcam.key) {
        sal_memcpy(f_ent->tcam.key_hw, f_ent->tcam.key, 
                   f_ent->tcam.key_size);
        sal_free(f_ent->tcam.key);
        f_ent->tcam.key = NULL;
    }
    if(NULL != f_ent->tcam.mask) {
        sal_memcpy(f_ent->tcam.mask_hw, f_ent->tcam.mask, 
                   f_ent->tcam.key_size);
        sal_free(f_ent->tcam.mask);
        f_ent->tcam.mask = NULL;
    }

    /* Then install the H/W copy into H/W */
    rv = fc->functions.fp_external_entry_reinstall(unit, f_ent);

    if (rv == BCM_E_NONE) {
        f_ent->flags &= ~_FP_ENTRY_DIRTY;
        f_ent->flags &= ~(_FP_ENTRY_ACTION_ONLY_DIRTY);
    }
    return (rv);
}

/*
 * Function:
 *     _field_tcam_policy_external_install
 *
 * Purpose:
 *     Install a combined TCAM and POLICY_TABLE entry. This writes the
 *     qualifiers and actions to the hardware.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Entry to be installed.
 *
 * Returns:
 *     BCM_E_INTERNAL  - Memory Read failure
 *     BCM_E_UNAVAIL   - Device not supported
 *     BCM_E_NONE      - Success
 *
 * Notes:
 */
STATIC int
_field_tcam_policy_external_install(int unit, _field_entry_t *f_ent)
{
    _field_control_t    *fc;         /* Field control structure.  */
    int                 rv;          /* Operation return status.  */


    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* If not installed, and no qualifiers yet  
     *     i.e. installing empty entry for first time
     */
    if (0 == (f_ent->flags & _FP_ENTRY_INSTALLED)) {
        BCM_IF_ERROR_RETURN (_bcm_field_qual_tcam_key_mask_get(unit, f_ent));
    }

    /* Next copy S/W copy to H/W copy if required */
    if(NULL != f_ent->tcam.key) {
        sal_memcpy(f_ent->tcam.key_hw, f_ent->tcam.key, 
                   f_ent->tcam.key_size);
        sal_free(f_ent->tcam.key);
        f_ent->tcam.key = NULL;
    }
    if(NULL != f_ent->tcam.mask) {
        sal_memcpy(f_ent->tcam.mask_hw, f_ent->tcam.mask, 
                   f_ent->tcam.key_size);
        sal_free(f_ent->tcam.mask);
        f_ent->tcam.mask = NULL;
    }

    /* Then install the H/W copy into H/W */
    rv = fc->functions.fp_external_entry_install(unit, f_ent);

    if (rv == BCM_E_NONE) {
        f_ent->flags &= ~_FP_ENTRY_DIRTY;
        f_ent->flags |= _FP_ENTRY_INSTALLED;
    }
    return (rv);
}

/*
 * Function:
 *     _field_hw_resources_free
 *
 * Purpose:
 *     Free hw resources used in FP entry.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Field entry structure. 
 *     flags     - (IN) Old/installed resource to free. 
 * Returns:
 *     BCM_E_XXX
 * Notes:
 */
STATIC int
_field_hw_resources_free(int unit, _field_entry_t *f_ent, uint32 flags)
{
    int rv;   /* Operation return status. */

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    /* Free redirection profiles. */
    rv = _field_redirect_profile_hw_free(unit, f_ent, flags);
    BCM_IF_ERROR_RETURN(rv);

    /* Free mirror destination indexes. */
    if (flags & _FP_ACTION_RESOURCE_FREE) {
        rv = _field_mtp_hw_free(unit, f_ent);
        BCM_IF_ERROR_RETURN(rv);
    }

    /* Free counters. */
    if (flags & _FP_ACTION_RESOURCE_FREE) {
        rv = _field_stat_hw_free(unit, f_ent);
        BCM_IF_ERROR_RETURN(rv);
    }

    /* Free policers. */
    if (flags & _FP_ACTION_RESOURCE_FREE) {
        rv = _field_policers_hw_free(unit, f_ent);
        BCM_IF_ERROR_RETURN(rv);
    }

#if defined(INCLUDE_L3)
#if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (soc_feature(unit, soc_feature_field_action_l2_change)) {
        rv = _bcm_field_l2_actions_hw_free(unit, f_ent, flags);
        BCM_IF_ERROR_RETURN(rv);
    }
#endif /* BCM_TRIUMPH2_SUPPORT || BCM_TRIDENT_SUPPORT */
#endif /* INCLUDE_L3 */

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_hw_resources_alloc
 *
 * Purpose:
 *     Allocate hw resources required for entry installation.
 *
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     f_ent     - (IN) Entry array
 * Returns:
 *     BCM_E_XXX
 * Notes:
 */
STATIC int
_field_hw_resources_alloc(int unit, _field_entry_t *f_ent)
{
    _field_stage_t   *stage_fc;    /* Stage field control.     */
    int rv;                        /* Operation return status. */

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    /* Get Stage Control structure. */
    rv = _field_stage_control_get(unit, f_ent->group->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Select slice for hw resources allocation. */
    rv = _field_entry_install_slice_fit(unit, stage_fc, f_ent, f_ent->fs);
    BCM_IF_ERROR_RETURN(rv);

    /* Allocate policers. */
    BCM_IF_ERROR_RETURN(_field_policers_hw_alloc(unit, f_ent));

    /* Allocate statistics. */
    rv = _field_stat_hw_alloc(unit, f_ent);
    if (BCM_FAILURE(rv)) {
        _field_policers_hw_free(unit, f_ent);
        return (rv);
    }

    /* Allocate mirror destination indexes. */
    rv = _field_mtp_hw_alloc(unit, f_ent);
    if (BCM_FAILURE(rv)) {
        _field_stat_hw_free(unit, f_ent);
        _field_policers_hw_free(unit, f_ent);
        return (rv);
    }

    /* Allocate redirection profiles. */
    rv = _field_redirect_profile_hw_alloc(unit, f_ent);
    if (BCM_FAILURE(rv)) {
        _field_mtp_hw_free(unit, f_ent);
        _field_stat_hw_free(unit, f_ent);
        _field_policers_hw_free(unit, f_ent);
        return (rv);
    }

#if defined (INCLUDE_L3)
#if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (soc_feature(unit, soc_feature_field_action_l2_change)) {
        rv =  _bcm_field_l2_actions_hw_alloc(unit, f_ent);
        if (BCM_FAILURE(rv)) {
            _field_mtp_hw_free(unit, f_ent);
            _field_stat_hw_free(unit, f_ent);
            _field_policers_hw_free(unit, f_ent);
            _field_redirect_profile_hw_free(unit, f_ent, _FP_ACTION_HW_FREE);
            return (rv);
        }
    }
#endif /* BCM_TRIUMPH2_SUPPORT || defined (BCM_TRIDENT_SUPPORT) */
#endif /* INCLUDE_L3 */

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_entry_actions_meter_slice_move
 * Purpose:
 *    Move actions to a slice where meter resides.   
 * Parameters:
 *     unit  - (IN) BCM device number.
 *     f_ent - (IN) Entry to be installed.
 *     to_secondary  - (IN) Movement direction.  
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_entry_actions_meter_slice_move(int unit, _field_entry_t *f_ent, int to_secondary)
{
    _field_stage_t   *stage_fc;   /* Stage field control.              */
    _field_action_t  *fa;         /* Entry actions iterator.           */
    _field_action_t  *fa_prev;    /* Entry actions iterator.           */
    _field_action_t  *fa_next;    /* Entry actions iterator.           */
    uint8            src_idx;     /* Entry array action source index.  */ 
    uint8            dst_idx;     /* Entry array action dest index.    */ 
    int              rv;          /* Operation return status.          */


    /* Input parameters check */
    if  (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    /* Get stage control structure. */
    rv = _field_stage_control_get(unit, f_ent->group->stage_id, &stage_fc); 
    BCM_IF_ERROR_RETURN(rv);

    if ((0 == (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS)) && 
        (f_ent->flags & _FP_ENTRY_POLICER_IN_SECONDARY_SLICE)) {
          rv = _bcm_field_entry_flags_to_tcam_part(_FP_ENTRY_SECONDARY, f_ent->group->flags, &dst_idx); 
          BCM_IF_ERROR_RETURN(rv);

          if (to_secondary) {
              src_idx = 0; 
          } else {
              src_idx = dst_idx; 
              dst_idx = 0; 
          }

          /* Copy all but counter action. */
          fa = f_ent[src_idx].actions;
          fa_prev = NULL;
          while (NULL != fa)  {
              fa_next = fa->next;
              if (fa->action != bcmFieldActionUpdateCounter) {
                 
                  /* Insert action to the destination slice actions list. */
                  fa->next = f_ent[dst_idx].actions;
                  f_ent[dst_idx].actions = fa;
                  /* Remove action from the primary slice actions list. */
                  if (NULL == fa_prev)  {
                      f_ent[src_idx].actions = fa_next;
                  } else {
                      fa_prev->next = fa_next;
                  }
              } else {
                  fa_prev = fa;
              }
              fa = fa_next;
          }
    }
    return (BCM_E_NONE);
}

/*
 * Function: _field_entry_tcam_remove
 *
 * Purpose:
 *     Remove an entry from the FP tcam.
 *
 * Parameters:
 *     unit     - (IN) BCM device number
 *     fc       - (IN) Field control structure. 
 *     f_ent    - (IN) Primary entry pointer.
 *     tcam_idx - (IN) Entry tcam index.
 *
 * Returns:
 *     BCM_E_XXX
 */
int
_field_entry_tcam_remove(int unit, _field_control_t *fc, 
                         _field_entry_t *f_ent, int tcam_idx)
{
    int rv;           /* Operation return status. */

    /* Input parameter check. */
    if ((NULL == fc) || (NULL == f_ent)) {
        return (BCM_E_PARAM);
    }
    /* Remove entry in slice. */
    if (f_ent->fs->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        rv = fc->functions.fp_external_entry_remove(unit, f_ent);
        BCM_IF_ERROR_RETURN(rv);
    } else {
        rv = fc->functions.fp_entry_remove(unit, f_ent, tcam_idx);
        BCM_IF_ERROR_RETURN(rv);
    }
    return (rv);
}

/*
 * Function:
 *     _field_tcam_policy_reinstall
 *
 * Purpose:
 *     Re-Install a POLICY_TABLE entry. This re-writes the
 *     modified actions to the hardware.
 *
 * Parameters:
 *     unit  - (IN) BCM device number.
 *     entry - (IN) Entry to be installed.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_tcam_policy_reinstall(int unit, bcm_field_entry_t entry)
{
    int                 tcam_idx[_FP_MAX_ENTRY_WIDTH]; /* Entry tcam index. */
    int                 parts_count;           /* Field entry parts count.  */
    _field_entry_t      *f_ent;                /* Field entry pointer.      */
    _field_control_t    *fc;                   /* Field control structure.  */
    int                 idx;                   /* Iteration index.          */
    int                 rv;                    /* Operation return status.  */


    FP_VVERB(("FP(unit %d) vverb: _field_tcam_policy_reinstall (%d)\n", unit, entry));
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Installing the entry. */
    rv = _bcm_field_entry_get_by_id(unit, entry, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get number of parts. */
    rv = _bcm_field_entry_tcam_parts_count (unit, f_ent->group->flags, 
                                            &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Get tcam indexes for installed entry. */
    if (f_ent->group->stage_id != _BCM_FIELD_STAGE_EXTERNAL) {
        for (idx = parts_count - 1; idx >=0; idx--) {
            rv = _bcm_field_entry_tcam_idx_get(unit, f_ent + idx, 
                                               tcam_idx + idx);
            BCM_IF_ERROR_RETURN(rv);
        }
    }

    /* Remove deleted actions. */
    rv = _field_invalid_actions_remove(unit, f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Allocate hw resources required for entry installation. */
    rv = _field_hw_resources_alloc(unit, f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Move  all actions to the slice where meter resides. */
    rv = _field_entry_actions_meter_slice_move(unit, f_ent, TRUE);
    if (BCM_FAILURE(rv)) {
        BCM_IF_ERROR_RETURN (_field_hw_resources_free(unit, f_ent, _FP_ACTION_HW_FREE));
        return (rv);
    }

    if (f_ent->group->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        rv = _field_tcam_policy_external_reinstall(unit, f_ent);
    }  else {
        for (idx = parts_count - 1; idx >=0; idx--) {

            FP_VVERB(("FP(unit %d) vverb: Part:%x EntryDirty:%x ActionOnlyDirty:%x\n", 
                unit, idx, (f_ent[idx].flags & _FP_ENTRY_DIRTY), 
                (f_ent[idx].flags & _FP_ENTRY_ACTION_ONLY_DIRTY)));

            /*
             * For Trident FP_GM_FIELDS.VALID = 1 when used in paired mode
             */
            if (SOC_IS_TD_TT(unit) && (idx == 1) &&
                (_BCM_FIELD_STAGE_INGRESS == f_ent->group->stage_id)) {
                    f_ent[idx].flags |= _FP_ENTRY_USES_IPBM_OVERLAY;
            }

            /* Get entry tcam key/mask. */
            rv = _bcm_field_qual_tcam_key_mask_get(unit, f_ent + idx);
            if (BCM_FAILURE(rv)) {
                break;
            }

            /* Install physical entry into primary slice */
            rv = fc->functions.fp_tcam_policy_reinstall(unit, f_ent + idx,
                                                      tcam_idx[idx]);
            if (BCM_FAILURE(rv)) {
                break;
            }

            f_ent[idx].flags &= ~_FP_ENTRY_DIRTY;
            f_ent[idx].flags &= ~(_FP_ENTRY_ACTION_ONLY_DIRTY);

            if(NULL != f_ent[idx].tcam.key) {
                sal_free(f_ent[idx].tcam.key);
            }

            if(NULL != f_ent[idx].tcam.mask) {
                sal_free(f_ent[idx].tcam.mask);
            }

            f_ent[idx].tcam.key = f_ent[idx].tcam.mask = NULL;
        }
    }

    if (BCM_FAILURE(rv)) {
        (void)_field_entry_actions_meter_slice_move(unit, f_ent, FALSE);
        (void)_field_hw_resources_free(unit, f_ent, _FP_ACTION_HW_FREE);
        return (rv);
    }

    /* Move  all actions back to the primary slice . */
    rv = _field_entry_actions_meter_slice_move(unit, f_ent, FALSE);
    if (BCM_FAILURE(rv)) {
        BCM_IF_ERROR_RETURN (_field_hw_resources_free(unit, f_ent, _FP_ACTION_HW_FREE));
        return (rv);
    }

    /* In case of entry reinstall free previous installation hw resources. */
    rv = _field_hw_resources_free(unit, f_ent, _FP_ACTION_OLD_RESOURCE_FREE);
    if (BCM_FAILURE(rv)) {
        BCM_IF_ERROR_RETURN (_field_hw_resources_free(unit, f_ent, _FP_ACTION_HW_FREE));
        return (rv);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_tcam_policy_install
 *
 * Purpose:
 *     Install a combined TCAM and POLICY_TABLE entry. This writes the
 *     qualifiers and actions to the hardware.
 *
 * Parameters:
 *     unit  - (IN) BCM device number.
 *     entry - (IN) Entry to be installed.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_tcam_policy_install(int unit, bcm_field_entry_t entry)
{
    int                 tcam_idx[_FP_MAX_ENTRY_WIDTH]; /* Entry tcam index. */
    int                 parts_count;           /* Field entry parts count.  */
    _field_entry_t      *f_ent;                /* Field entry pointer.      */
    _field_control_t    *fc;                   /* Field control structure.  */
    int                 idx;                   /* Iteration index.          */
    int                 rv;                    /* Operation return status.  */
#if defined(BCM_KATANA_SUPPORT)
    uint32                       stat_counter_id=0;
    bcm_stat_object_t            object=bcmStatObjectIngPort;
    bcm_stat_group_mode_t        group_mode= bcmStatGroupModeSingle;
    uint32                       base_index=0;
    bcm_stat_flex_mode_t         offset_mode=0;
    uint32                       pool_number=0;
    _field_stat_t                *f_st=NULL;
    _field_entry_stat_t          *f_ent_st=NULL;
#endif

    FP_VVERB(("FP(unit %d) vverb: bcm_field_policy_install (%d)\n", unit, entry));
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Installing the entry. */
    rv = _bcm_field_entry_get_by_id(unit, entry, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get number of parts. */
    rv = _bcm_field_entry_tcam_parts_count (unit, f_ent->group->flags, 
                                            &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Get tcam indexes for installed entry. */
    if (f_ent->group->stage_id != _BCM_FIELD_STAGE_EXTERNAL) {
        for (idx = parts_count - 1; idx >=0; idx--) {
            rv = _bcm_field_entry_tcam_idx_get(unit, f_ent + idx, 
                                               tcam_idx + idx);
            BCM_IF_ERROR_RETURN(rv);
        }
    }

    /* If entry was previously installed, we better disable it temporarily, 
     * to avoid intermittent actions. 
     */
    if (f_ent->flags & _FP_ENTRY_INSTALLED) {
        for (idx = 0; idx < parts_count; idx++) {
            /* Read existing entry qualifiers from the HW. */
            rv = _bcm_field_qual_tcam_key_mask_get(unit, f_ent + idx);
            BCM_IF_ERROR_RETURN(rv);

            /* Disable installed entry. */
            rv = _field_entry_tcam_remove(unit, fc, f_ent + idx, tcam_idx[idx]); 
            BCM_IF_ERROR_RETURN(rv);
        }
    }

    /* Remove deleted actions. */
    rv = _field_invalid_actions_remove(unit, f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Allocate hw resources required for entry installation. */
    rv = _field_hw_resources_alloc(unit, f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Move  all actions to the slice where meter resides. */
    rv = _field_entry_actions_meter_slice_move(unit, f_ent, TRUE);
    if (BCM_FAILURE(rv)) {
        BCM_IF_ERROR_RETURN (_field_hw_resources_free(unit, f_ent, _FP_ACTION_HW_FREE));
        return (rv);
    }

    if (f_ent->group->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        rv = _field_tcam_policy_external_install(unit, f_ent);
    }  else {
        for (idx = parts_count - 1; idx >=0; idx--) {
            /*
             * For Trident FP_GM_FIELDS.VALID = 1 when used in paired mode
             */
            if (SOC_IS_TD_TT(unit) && (idx == 1) &&
                (_BCM_FIELD_STAGE_INGRESS == f_ent->group->stage_id)) {
                    f_ent[idx].flags |= _FP_ENTRY_USES_IPBM_OVERLAY;
            }

            /* Get entry tcam key/mask. */
            rv = _bcm_field_qual_tcam_key_mask_get(unit, f_ent + idx);
            if (BCM_FAILURE(rv)) {
                break;
            }

            /* Install physical entry into primary slice */
            rv = fc->functions.fp_tcam_policy_install(unit, f_ent + idx,
                                                      tcam_idx[idx]);
            if (BCM_FAILURE(rv)) {
                break;
            }
#if defined(BCM_KATANA_SUPPORT)
            if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
                  if (_BCM_FIELD_STAGE_LOOKUP == f_ent->group->stage_id)   {
                 f_ent_st= &f_ent->statistic;
                 if(_bcm_field_stat_get(unit,f_ent_st->sid,&f_st)
                    == BCM_E_NONE) {
                    if(f_st->flex_mode != 0) {
                       soc_cm_print("Attaching Flex counter...\n");
                       stat_counter_id = f_st->flex_mode;
                       _bcm_esw_stat_get_counter_id_info(
                            stat_counter_id,
                            &group_mode,&object,&offset_mode,
                            &pool_number,&base_index);
                       if(_bcm_esw_stat_flex_attach_ingress_table_counters(
                          unit, VFP_POLICY_TABLEm, tcam_idx[idx],
                          offset_mode, base_index, pool_number) == BCM_E_NONE) {
                         f_st->tcam_index = tcam_idx[idx];
                       }
                    }
                 }
              }
            }
#endif
            f_ent[idx].flags &= ~_FP_ENTRY_DIRTY;
            f_ent[idx].flags |= _FP_ENTRY_INSTALLED;
            if(NULL != f_ent[idx].tcam.key) sal_free(f_ent[idx].tcam.key);
            if(NULL != f_ent[idx].tcam.mask) sal_free(f_ent[idx].tcam.mask);
            f_ent[idx].tcam.key = f_ent[idx].tcam.mask = NULL;
        }
    }

    if (BCM_FAILURE(rv)) {
        (void)_field_entry_actions_meter_slice_move(unit, f_ent, FALSE);
        (void)_field_hw_resources_free(unit, f_ent, _FP_ACTION_HW_FREE);
        return (rv);
    }

    /* Move  all actions back to the primary slice . */
    rv = _field_entry_actions_meter_slice_move(unit, f_ent, FALSE);
    if (BCM_FAILURE(rv)) {
        BCM_IF_ERROR_RETURN (_field_hw_resources_free(unit, f_ent, _FP_ACTION_HW_FREE));
        return (rv);
    }

    /* In case of entry reinstall free previous installation hw resources. */
    rv = _field_hw_resources_free(unit, f_ent, _FP_ACTION_OLD_RESOURCE_FREE);
    if (BCM_FAILURE(rv)) {
        BCM_IF_ERROR_RETURN (_field_hw_resources_free(unit, f_ent, _FP_ACTION_HW_FREE));
        return (rv);
    }
    return (BCM_E_NONE);
}


/*
 * Function: _field_entry_remove
 *
 * Purpose:
 *     Remove an entry from the hardware tables.
 *
 * Parameters:
 *     unit  - (IN) BCM device number
 *     fc    - (IN) Field control structure. 
 *     entry - (IN) Entry to remove.
 *
 * Returns:
 *     BCM_E_XXX
 */
int
_field_entry_remove(int unit, _field_control_t *fc, bcm_field_entry_t entry)
{
    _field_entry_t      *f_ent;      /* Field entry pointer.     */
    int                 tcam_idx;    /* Entry tcam index.        */
    int                 parts_count; /* Entry parts count.       */
    int                 idx;         /* Iteration index.         */
    int                 rv;          /* Operation return status. */

    rv = _bcm_field_entry_get_by_id(unit, entry, &f_ent);
    if (BCM_FAILURE(rv)) {
        return (rv);
    }

    /* Get number of parts. */
    rv = _bcm_field_entry_tcam_parts_count (unit, f_ent->group->flags, 
                                            &parts_count);

    for (idx = 0; idx < parts_count; idx++) {
        /* Store entry in S/W before removing from H/W */
        rv = _bcm_field_qual_tcam_key_mask_get(unit, f_ent + idx);
        BCM_IF_ERROR_RETURN(rv);

        /* Get entry tcam index. */
        rv = _bcm_field_entry_tcam_idx_get(unit, f_ent + idx, &tcam_idx);
        BCM_IF_ERROR_RETURN(rv);

        /* Remove entry in slice. */

        rv = _field_entry_tcam_remove(unit, fc, f_ent + idx, tcam_idx); 
        BCM_IF_ERROR_RETURN(rv);

        f_ent[idx].flags |= _FP_ENTRY_DIRTY;
        f_ent[idx].flags &= ~_FP_ENTRY_INSTALLED;
    }

    /* Free hw resources allocated during entry installation. */
    rv = _field_hw_resources_free(unit, f_ent, _FP_ACTION_RESOURCE_FREE);
    BCM_IF_ERROR_RETURN(rv);

    /* Remove deleted actions. */
    rv = _field_invalid_actions_remove(unit, f_ent);
    BCM_IF_ERROR_RETURN(rv);
    return (BCM_E_NONE);
}


/* Function: _field_reqd_prio_set_move
 *
 * Purpose: Checks if the entry needs to be moved due to prio set
 *
 * Parameters: 
 *   unit - 
 *   f_ent - Entry whose priority is being set
 *   prio - The new priority for f_ent
 *
 * Returns:
 *   TRUE/FALSE
 */
int
_field_reqd_prio_set_move(int unit, _field_entry_t *f_ent, int prio)
{
    _field_group_t *fg;
    _field_slice_t *fs;
    _field_stage_t *stage_fc;
    int slice_sz;

    int i, flag; /* flag denotes is we are before OR after f_ent */

    fg = f_ent->group;

    /* Get stage control structure. */
    BCM_IF_ERROR_RETURN
        (_field_stage_control_get(unit, fg->stage_id, &stage_fc));

    fs = &fg->slices[0];
    flag = -1; /* We are before f_ent */
    while (fs != NULL) {
        _BCM_FIELD_ENTRIES_IN_SLICE(fg, fs, slice_sz);
        for (i = 0; i < slice_sz; i++) {
            if (fs->entries[i] == f_ent) {
                flag = 1; /* Now, we are after f_ent */
                continue;
            }
            if (fs->entries[i] == NULL) {
                continue;
            }
            if (flag == -1) {
                if (_field_entry_prio_cmp(fs->entries[i]->prio, prio) < 0) {
                            /* 
                     * An entry before f_ent has lower priority than prio
                     *     Movement is required 
                     */
                    return TRUE; 
                }
            } else {
                if (_field_entry_prio_cmp(fs->entries[i]->prio, prio) > 0) {
                            /* 
                     * An entry after f_ent has higher priority than prio
                     *     Movement is required 
                     */
                    return TRUE;
                }
            }
        }
        fs = fs->next;
    }
    return FALSE; /* f_ent with new prio is in proper location */
}

/*
 * Function: _field_entry_multiple_slice_move_check
 *
 * Purpose: Checks if a series of entries can be shifted to the
 *          nearest hole and returns how many entries would end up
 *          being shifted.
 *
 *          This function is called recursively for each slice in
 *          which entries need to be shifted.
 *
 * Parameters:
 *   unit - unit
 *   fg - The group to which the slices belong
 *   entry - Pointer to the entry which is being moved
 *   null_index - Index of the next empty slot within its slice, in the
 *                specified direction
 *   null_fs - Pointer to the next slice with an empty slot, in the
 *             specified direction
 *   target_index - Index of the slot in which we want to insert the entry
 *   target_fs - Pointer to the slice in which we want to insert the entry
 *   direction - The direction in which we're checking entry shifting
 *               feasibility; -1 for up or 1 for down
 *   shifted_entry_count (IN/OUT) - The number of entries that would be shifted
 *                               to make the move possible
 *   freed_counter_count (IN/OUT) - The number of counters that would be freed
 *                               by the shift
 *
 * Returs:
 *   BCM_E_NONE if the move can be done
 */

STATIC int _field_entry_multiple_slice_move_check(int unit,
    _field_group_t *fg, _field_entry_t *entry, int null_index,
    _field_slice_t *null_fs, int target_index, _field_slice_t *target_fs,
    int direction, int *shifted_entry_count, int *freed_meter_count,
    int *freed_counter_count)
{
    int rv = BCM_E_NONE;
    _field_stage_t *stage_fc;
    _field_slice_t *adjacent_fs;
    int adjacent_index;
    int slice_entry_count;
    int adjacent_slice_entry_count;
    _field_entry_t *entry_to_move;

    BCM_IF_ERROR_RETURN
        (_field_stage_control_get(unit, target_fs->stage_id, &stage_fc));

    _BCM_FIELD_ENTRIES_IN_SLICE(fg, target_fs, slice_entry_count);

    if (target_fs != null_fs)
    {
        if (direction < 0)
        {
            /* Shift up */

            adjacent_fs = target_fs->prev;

            _BCM_FIELD_ENTRIES_IN_SLICE(fg, adjacent_fs,
                adjacent_slice_entry_count);

            adjacent_index = adjacent_slice_entry_count - 1;
            entry_to_move = target_fs->entries[0];
            *shifted_entry_count += target_index;
        }
        else
        {
            /* Shift down */

            adjacent_fs = target_fs->next;
            adjacent_index = 0;
            entry_to_move = target_fs->entries[slice_entry_count - 1];
            *shifted_entry_count += slice_entry_count - target_index;
        }

        rv = _field_entry_multiple_slice_move_check(unit, fg,
            entry_to_move, null_index, null_fs, adjacent_index,
            adjacent_fs, direction, shifted_entry_count, freed_meter_count,
            freed_counter_count);

        BCM_IF_ERROR_RETURN(rv);
    }
    else
    {
        *shifted_entry_count += direction * (null_index - target_index);
    }

    if (entry->fs != target_fs)
    {
        rv = _field_entry_move_slice_fit(unit, stage_fc, entry, target_fs,
            freed_meter_count, freed_counter_count);
    }

    return rv;
}

/*
 * Function: _field_validate_prio_set
 *
 * Purpose: Checks if the prio_set can be successful.
 *     Meaningful only when entries need to be moved across slices
 *     1. Check that entries moving across slices don't have shared 
 *        meters/counters
 *     2. For entries moving across slices, and having meters/counters,
 *        check if there are resources in the new slice
 *
 * Parameters:
 *   unit - unit
 *   fg - group the entry whose prio is being set belongs to
 *   f_ent_pri - primary entry whose priorty is to be changed
 *   prev_null_index - index with no entry just before target_index
 *   prev_null_fs - corresponding slice
 *   target_index - the target index where f_ent is supposed to go
 *   target_fs - the slice where index resides
 *   next_null_index - index with no entry just after target_index
 *   next_null_fs - corresponding slice
 *   dir (OUT) - shift up (-1) or down (+1)
 *
 * Returs:
 *   TRUE/FALSE
 *
 * Notes:
 *     Check both up and down movement. If both feasible, take the one
 *     which leads to lesser moves.
 *     Note the slice_sz for intraslice-double wide (FB2). Also shift_up_amount
 *     and shift_down_amount are not absolute amounts, but # entries which 
 *     need to be shifted (each entry moves by 1 unit UP/DOWN).
 */
STATIC int
_field_validate_prio_set(int unit, 
                         _field_group_t *fg, _field_entry_t *f_ent_pri, 
                         int prev_null_index, _field_slice_t *prev_null_fs,
                         int target_index, _field_slice_t *target_fs,
                         int next_null_index, _field_slice_t *next_null_fs,
                         int *dir)
{
    _field_stage_t *stage_fc;
    int rv;
    int shift_up = FALSE, shift_down = FALSE;
    int shift_up_amount = 0, shift_down_amount = 0;
    int up_meters_freed = 0, down_meters_freed = 0;
    int up_counters_freed = 0, down_counters_freed = 0;

    /* Input parameter check. */ 
    if ((NULL == f_ent_pri) || (NULL == target_fs)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN
        (_field_stage_control_get(unit, target_fs->stage_id, &stage_fc));

    /* 
     * STEP-1
     * Check the shift operation for UP movement
     * Entries from target_index up till entry after prev_null_index
     * need to move one entry up
     */

    if (prev_null_fs != NULL)
    {
        rv = _field_entry_multiple_slice_move_check(unit, fg, f_ent_pri,
            prev_null_index, prev_null_fs, target_index, target_fs, -1,
            &shift_up_amount, &up_meters_freed, &up_counters_freed);

        shift_up = BCM_SUCCESS(rv);
    }
    else
    {
        shift_up = FALSE;
    }

    /* 
     * Step-2
     * Check the shift operation for DOWN movement
     * Entries from target_index till entry before next_null_index
     * need to move one entry down
     */

    if (next_null_fs != NULL)
    {
        rv = _field_entry_multiple_slice_move_check(unit, fg, f_ent_pri,
            next_null_index, next_null_fs, target_index, target_fs, 1,
            &shift_down_amount, &down_meters_freed, &down_counters_freed);

        shift_down = BCM_SUCCESS(rv);
    }
    else
    {
        shift_down = FALSE;
    }

    if (shift_up == TRUE)
    {
        if (shift_down == TRUE)
        {
            if (shift_up_amount < shift_down_amount)
            {
                *dir = -1;
            }
            else
            {
                *dir = 1;
            }
        }
        else
        {
            *dir = -1;
        }
    }
    else
    {
        if (shift_down == TRUE)
        {
            *dir = 1;
        }
        else
        {
            return FALSE;
        }
    }

    return TRUE;
}

/*
 * Function: _field_no_free_entries
 *
 * Purpose:
 *     To see if the any of the slices allocated to this
 *     group has any free entries
 *
 * Parameters:
 *     unit - BCM device number
 *     fg - group
 *
 * Returns:
 *     FALSE: Atleast 1 free entry
 *     TRUE: No free entries
 *
 * Notes: 
 */
int
_field_no_free_entries(int unit, _field_group_t *fg)
{
    _field_slice_t *fs;
    int free_entry_cnt;

    fs = &fg->slices[0];

    while (fs != NULL) {
        _field_entries_free_get(unit, fs, fg, &free_entry_cnt);
        if (free_entry_cnt) {
            return FALSE;
        }
        fs = fs->next;
    }

    return TRUE;
}

/*
 * Function:
 *     _field_entry_prio_cmp
 * Purpose:
 *     Compare two entry priorities
 * Parameters:
 * Returns:
 *     -1 if prio_first <  prio_second
 *      0 if prio_first == prio_second
 *      1 if prio_first >  prio_second
 */
int
_field_entry_prio_cmp(int prio_first, int prio_second)
{
    int retval;

    if (prio_first == prio_second) {
        retval = 0;
    } else if (prio_first < prio_second) {
        retval = -1;
    } else {
        retval = 1;
    }
    return retval;
}


/*
 * Function:
 *     _field_entry_move
 * Purpose:
 *     Move an entry within a slice by "amount" indexes
 *     
 * Parameters:
 *     unit     - BCM device number
 *     f_ent    - entry to be moved
 *     amount   - number of indexes to move + or -
 * Returns:
 *     BCM_E_NONE   - Success
 */
STATIC int
_field_entry_move(int unit, _field_entry_t *f_ent, int amount)
{
    int  tcam_idx_old[_FP_MAX_ENTRY_WIDTH];/* Original entry tcam index.    */ 
    int  tcam_idx_new[_FP_MAX_ENTRY_WIDTH];/* Next tcam index for the entry.*/ 
    _field_entry_policer_t *f_ent_pl;   /* Field entry policer structure.*/
    _field_entry_stat_t    *f_ent_st;   /* Field entry stat structure.   */
    _field_control_t       *fc;         /* Field control structure.      */
    _field_stage_t         *stage_fc;   /* Stage field control.          */
    _field_group_t         *fg;         /* Field entry group.            */
    _field_slice_t         *fs;         /* Field slice control.          */
    _field_entry_t         *f_ent_sec = NULL;
    _field_policer_t       *f_pl = NULL;/* Field policer info.           */  
    _field_stat_t          *f_st = NULL;/* Field statatistics entity.    */ 
    int                    parts_count; /* Field entry parts count.      */
    int                     idx;
    int                    rv;          /* Operation return status.      */
    int counter_movement = 0; /* Boolean which tells if entry moved across 
                                 slice, and if so, did it have a counter */
    uint8 entry_part;                    /* Field entry parts iterator.  */ 
    int meter_movement   = 0; /* For meter */
    int meter_index      = 0; 
    int meter_pool_index = 0;
    int stat_index       = 0;
    int stat_slice       = 0;
    int new_offset; 
    int new_slice_numb   = 0;
    _field_stat_t f_st_old;             /* Old Field statatistics entity. */ 

    FP_VVERB(("FP(unit %d) vverb: BEGIN _field_entry_move(entry=%d, amount=%d)\n", 
              unit, f_ent->eid, amount));

    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }
    
    if ((NULL == f_ent->fs) || (NULL == f_ent->group)) {
        return (BCM_E_PARAM);
    }

    /* Initialization. */
    sal_memset(tcam_idx_old, 0,  (_FP_MAX_ENTRY_WIDTH * sizeof(int)));
    sal_memset(tcam_idx_new, 0, (_FP_MAX_ENTRY_WIDTH * sizeof(int)));
    fg = f_ent->group;

    if (amount == 0) {
        FP_WARN(("FP(unit %d) warn:  moving entry=%d, same slice_idx=%d(%#x)\n",
                 unit, f_ent->eid, f_ent->slice_idx, f_ent->slice_idx));
        return (BCM_E_NONE);
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN (_field_control_get(unit, &fc));

    /* Get stage field control structure. */
    rv =  _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Get number of parts. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Calculate the new and old TCAM indexes. */
    for (idx = 0; idx < parts_count; idx++) {
        /* Calculate the new and old TCAM indexes. */
        rv = _bcm_field_entry_tcam_idx_get(unit, f_ent + idx,
                                           &tcam_idx_old[idx]);
        BCM_IF_ERROR_RETURN(rv);

        /* Calculate entry part tcam offset. */
        rv = _bcm_field_entry_part_tcam_idx_get(unit, f_ent, 
                                                tcam_idx_old[0] + amount,
                                                idx, &tcam_idx_new[idx]);
        BCM_IF_ERROR_RETURN(rv);
    }

    /* Get secondary slice entry pointer. */
    if ((fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) ||
        (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE)) {
        rv = _bcm_field_entry_flags_to_tcam_part (_FP_ENTRY_SECONDARY, 
                                                  fg->flags, &entry_part);
        BCM_IF_ERROR_RETURN(rv);
        f_ent_sec =  f_ent + entry_part;
    } else {
        f_ent_sec =  NULL;
    }

    /* Calculate entry new slice number. */
    rv = _bcm_field_tcam_idx_to_slice_offset (unit, stage_fc,
                                              tcam_idx_new[0],
                                              &new_slice_numb, &new_offset);
    BCM_IF_ERROR_RETURN(rv);

    if ((f_ent->fs->slice_number != new_slice_numb) &&
        (f_ent->flags  & _FP_ENTRY_INSTALLED)) {


        fs = stage_fc->slices + new_slice_numb;

        /* 
         * If global meter pools are not present, AND
         *     current entry has a meter, allocate one in new slice 
         */
        f_ent_pl = f_ent->policer;
        if ((0 == (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS)) &&
            (f_ent_pl->flags & _FP_POLICER_INSTALLED))  {
            meter_movement = 1;

            /* Read policer configuration.*/
            rv = _bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl);
            BCM_IF_ERROR_RETURN(rv);

            /* Preserve original policer hw index. */
            meter_pool_index = f_pl->pool_index;
            meter_index = f_pl->hw_index;

            /* Deallocate policer from original entry slice. */ 
            BCM_IF_ERROR_RETURN (_field_meter_hw_free(unit, f_ent));

            /* Allocate policer in a new slice. */ 
            BCM_IF_ERROR_RETURN (_field_meter_hw_alloc(unit, f_ent, fs));
        }

        /* 
         * If global counters are not present, AND
         *     current entry has a counter, allocate one in new slice 
         *  NOTE: Must be after policer allocation in order to
         *  determine counter slice.
         */
        f_ent_st = &f_ent->statistic;
        if ((0 == (stage_fc->flags & _FP_STAGE_GLOBAL_COUNTERS)) && 
            (f_ent_st->flags & _FP_ENTRY_STAT_INSTALLED))  {
            counter_movement = 1;

            /* Read statistics entity configuration.*/
            BCM_IF_ERROR_RETURN(_bcm_field_stat_get(unit, f_ent_st->sid, &f_st));
            f_st_old = *f_st;

            /* Preserve original policer hw index. */
            stat_slice = f_st->pool_index;
            stat_index = f_st->hw_index;

            /* Deallocate statistics entity from original entry slice. */ 
            BCM_IF_ERROR_RETURN(_field_slice_counter_free(unit, f_ent, f_st));

            /* Allocate statistics entity in a new slice. */ 
            BCM_IF_ERROR_RETURN(_field_counter_hw_alloc(unit, f_ent, fs));
        }
    }

    /* Move the hardware entry.*/
    if (f_ent->flags  & _FP_ENTRY_INSTALLED) {
        rv = fc->functions.fp_entry_move(unit, f_ent, parts_count, 
                                         tcam_idx_old, tcam_idx_new);
        BCM_IF_ERROR_RETURN(rv);
    }

    /* Move the software entry.*/
    rv = _field_entry_slice_idx_change(unit, f_ent, parts_count, tcam_idx_new);
    BCM_IF_ERROR_RETURN(rv);

    if (meter_movement) {
        f_ent_pl = f_ent->policer;
        /* Read policer configuration. */
        rv = _bcm_field_policer_get (unit, f_ent_pl->pid, &f_pl);
        BCM_IF_ERROR_RETURN(rv);

        rv = _field_entry_meter_move (unit, stage_fc, meter_pool_index, 
                                      meter_index, f_pl);
        BCM_IF_ERROR_RETURN(rv);
    }

    if (counter_movement) {
        f_ent_st = &f_ent->statistic;
        BCM_IF_ERROR_RETURN (_bcm_field_stat_get (unit, f_ent_st->sid, &f_st));
        rv = _bcm_field_entry_counter_move(unit, stage_fc, stat_slice,
                stat_index, &f_st_old, f_st);
        BCM_IF_ERROR_RETURN(rv);
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_qualify_macaddr_get
 * Purpose:
 *     Get qualifier Source or Destination mac address.
 *
 * Parameters:
 *     unit     - (IN) BCM device number
 *     entry    - (IN) Field entry to qualify on
 *     qual     - (IN) Field qualifier id.
 *     data     - (OUT)Data to qualify with (type varies)
 *     mask     - (OUT)Mask to qualify with (type is same as for data)
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized.
 *     BCM_E_XXX       - Other errors
 */
STATIC int
_field_qualify_macaddr_get(int unit, bcm_field_entry_t entry,
                           bcm_field_qualify_t qual, 
                           bcm_mac_t *data, bcm_mac_t *mask)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t           *f_ent;
    uint32                   ref_data[_FP_QUAL_DATA_WORDS]; 
    uint32                   ref_mask[_FP_QUAL_DATA_WORDS];
    int                      rv;

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

    /* Read qualifier match value and mask. */
    rv = _bcm_field_qual_value_get(unit, q_offset, f_ent, 
                                   ref_data, ref_mask);
    BCM_IF_ERROR_RETURN(rv);

    SAL_MAC_ADDR_FROM_UINT32((*data), ref_data);
    SAL_MAC_ADDR_FROM_UINT32((*mask), ref_mask);

    return (BCM_E_NONE);
} 

/*
 * Function:
 *     _field_qualify_macaddr
 * Purpose:
 *     Qualify on a Source or Destination mac address.
 *
 * Parameters:
 *     unit     - (IN) BCM device number
 *     entry    - (IN) Field entry to qualify on
 *     qual     - (IN) Field qualifier id.
 *     data     - (IN) Data to qualify with (type varies)
 *     mask     - (IN) Mask to qualify with (type is same as for data)
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized.
 *     BCM_E_XXX       - Other errors
 */
STATIC int
_field_qualify_macaddr(int unit, bcm_field_entry_t entry,
                    bcm_field_qualify_t qual, 
                    bcm_mac_t data, bcm_mac_t mask)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t           *f_ent;
    uint32                   ref_data[_FP_QUAL_DATA_WORDS]; 
    uint32                   ref_mask[_FP_QUAL_DATA_WORDS];
    int                      rv;

    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

    SAL_MAC_ADDR_TO_UINT32(data, ref_data);
    SAL_MAC_ADDR_TO_UINT32(mask, ref_mask);

    /* Program data/mask pair to tcam buffer. */
    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, ref_data, ref_mask);
    return (rv);
}

/*
 * Function:
 *     _field_qualify_Port
 * Purpose:
 *     Qualify on a Source or Destination Port.
 *
 * Parameters:
 *     unit       - BCM device number
 *     entry      - Field entry to qualify on
 *     data_modid - Data to qualify with (type varies)
 *     mask_modid - Mask to qualify with (type is same as for data)
 *     data_port  - Data to qualify with (type varies)
 *     mask_port  - Mask to qualify with (type is same as for data)
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized.
 *     BCM_E_INTERNAL  - qual neither SrcPort or DstPort
 *     BCM_E_NOT_FOUND - Entry ID not found in unit.
 *     BCM_E_PARAM     - port data out of range
 *     BCM_E_XXX       - Other errors
 */
STATIC int
_field_qualify_Port(int unit, bcm_field_entry_t entry,
                    bcm_module_t data_modid, bcm_module_t mask_modid,
                    bcm_port_t   data_port,  bcm_port_t   mask_port,
                    bcm_field_qualify_t qual)
{
    uint32 mod_port_data = 0;   /* concatenated modid and port */
    uint32 mod_port_mask = 0;   /* concatenated modid and port */

    if (qual != bcmFieldQualifySrcPort && qual != bcmFieldQualifyDstPort) {
        FP_ERR(("FP(unit %d) Error: _field_qualify_Port() only works with SrcPort or " 
                "DstPort \n", unit));
        return (BCM_E_INTERNAL);
    }

    /* Range check data port */
    if (!SOC_PORT_ADDRESSABLE(unit, data_port)) {
        FP_ERR(("FP(unit %d) Error: data_port=%#x too large\n", unit, data_port));
        return (BCM_E_PARAM);
    }

    /* Set masks to all ones if exact match is specified. */
    if (mask_modid == BCM_FIELD_EXACT_MATCH_MASK) {
        mask_modid = SOC_MODID_MAX(unit);
    }

    if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
        /* Trunk Bit (Tf) is not with Trunk/Port ID */
        int num_bits_for_port;
        if (mask_port == BCM_FIELD_EXACT_MATCH_MASK) {
            mask_port = SOC_PORT_ADDR_MAX(unit);
        }
        num_bits_for_port = _shr_popcount((unsigned int)SOC_PORT_ADDR_MAX(unit));

        mod_port_data = (data_modid << num_bits_for_port) | data_port;
        mod_port_mask = (mask_modid << num_bits_for_port) | mask_port;

        /* Clear the trunk ID bit. */
        mod_port_data &= ~(1 << SOC_TRUNK_BIT_POS(unit));
        /* Must match on the T bit (which should be 0) */
        mod_port_mask |= (1 << SOC_TRUNK_BIT_POS(unit)); 

        if (bcmFieldQualifyDstPort == qual) {
            BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit,
                entry, qual, &mod_port_data, &mod_port_mask, 0));
        }

        return _field_qualify32(unit, entry, qual, mod_port_data, mod_port_mask);
    }

    /* Note: Trunk bit is the MSB in PORT_TGID */
    if (mask_port == BCM_FIELD_EXACT_MATCH_MASK) {
        mask_port = (1 << (SOC_TRUNK_BIT_POS(unit) + 1)) - 1;
    }

    /* Combine module IDs and ports */
    mod_port_data = (data_modid << (SOC_TRUNK_BIT_POS(unit) + 1)) | data_port; 
    mod_port_mask = (mask_modid << (SOC_TRUNK_BIT_POS(unit) + 1)) | mask_port; 

    /* Clear the trunk ID bit. */
    mod_port_data &= ~(1 << SOC_TRUNK_BIT_POS(unit));
    /* Must match on the T bit (which should be 0) */
    mod_port_mask |= (1 << SOC_TRUNK_BIT_POS(unit)); 

    if (bcmFieldQualifyDstPort == qual) {
        BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit,
            entry, qual, &mod_port_data, &mod_port_mask, 0));
    }

    return _field_qualify32(unit, entry, qual, mod_port_data, mod_port_mask);
}


/*
 * Function:
 *     _field_qualify_Port_get
 * Purpose:
 *     Qualify on a Source or Destination Port.
 *
 * Parameters:
 *     unit       - BCM device number
 *     entry      - Field entry to qualify on
 *     data_modid - Data to qualify with (type varies)
 *     mask_modid - Mask to qualify with (type is same as for data)
 *     data_port  - Data to qualify with (type varies)
 *     mask_port  - Mask to qualify with (type is same as for data)
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized.
 *     BCM_E_INTERNAL  - qual neither SrcPort or DstPort
 *     BCM_E_NOT_FOUND - Entry ID not found in unit.
 *     BCM_E_PARAM     - port data out of range
 *     BCM_E_XXX       - Other errors
 */
STATIC int
_field_qualify_Port_get(int unit, bcm_field_entry_t entry,
                        bcm_module_t *data_modid, 
                        bcm_module_t *mask_modid,
                        bcm_port_t   *data_port,  
                        bcm_port_t   *mask_port,
                        bcm_field_qualify_t qual)
{
    uint32    mod_port_data = 0; /* Concatenated modid and port */
    uint32    mod_port_mask = 0; /* Concatenated modid and port */
    int       rv;                /* Operation return stauts.    */
    int       num_bits_for_port; /* Port field size.            */
    int       trunk_bit_pos = 0;

    /* Input parameter check. */
    if ((NULL == data_modid) || (NULL == mask_modid) ||
        (NULL == data_port) || (NULL == mask_port)) {
        return (BCM_E_PARAM);
    }
    /* Internal sanity check. */
    if (qual != bcmFieldQualifySrcPort && qual != bcmFieldQualifyDstPort) {
        return (BCM_E_INTERNAL);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, qual,
                                           (uint32 *)&mod_port_data, 
                                           (uint32 *)&mod_port_mask);
    BCM_IF_ERROR_RETURN(rv);

    if (qual == bcmFieldQualifyDstPort) {
        BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
            entry, qual, (uint32 *) &mod_port_data, (uint32 *) &mod_port_mask));
    }

    if (soc_feature(unit, soc_feature_trunk_group_overlay)) {

        num_bits_for_port = _shr_popcount((unsigned int)SOC_PORT_ADDR_MAX(unit));
        *data_modid =  mod_port_data >> num_bits_for_port;
        *mask_modid =  mod_port_mask >> num_bits_for_port;

        *data_port = mod_port_data & ((1 << num_bits_for_port) - 1);
        *mask_port = mod_port_mask & ((1 << num_bits_for_port) - 1);
        return (rv);
    }

    /* Get the trunk bit position */
    trunk_bit_pos = SOC_TRUNK_BIT_POS(unit);

    /* Get Modid Info */ 
    *data_modid =  mod_port_data >> (trunk_bit_pos + 1);
    *mask_modid =  mod_port_mask >> (trunk_bit_pos + 1);

    /* Get Port Info */ 
    *data_port = mod_port_data & ((1 << trunk_bit_pos) - 1);
    *mask_port = mod_port_mask & ((1 << trunk_bit_pos) - 1);
    return (rv);
}

#define _FIELD_TRUNK_BIT_INSERT(_u_, _t_)                       \
    ((((_t_) & BCM_TGID_PORT_TRUNK_MASK_HI(_u_)) << 1) |        \
     BCM_TGID_TRUNK_INDICATOR(_u_) | ((_t_) & BCM_TGID_PORT_TRUNK_MASK(_u_)))

#define _FIELD_TRUNK_BIT_RESET(_u_, _t_)                        \
    ((((_t_) - ((_t_) & BCM_TGID_PORT_TRUNK_MASK(_u_))) >> 1) | \
     ((_t_) & BCM_TGID_PORT_TRUNK_MASK(_u_)))


/*
 * Function:
 *     _field_qualify_Trunk
 * Purpose:
 *     Qualify on a Source or Destination Trunk ID.
 *
 * Parameters:
 *     unit       - BCM device number
 *     entry      - Field entry to qualify on
 *     data       - Trunk ID to qualify
 *     mask       - Trunk mask to qualify
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized.
 *     BCM_E_INTERNAL  - qual neither SrcPort or DstPort
 *     BCM_E_NOT_FOUND - Entry ID not found in unit.
 *     BCM_E_PARAM     - Trunk ID or mask out of range
 *     BCM_E_XXX       - Other errors
 */
STATIC int
_field_qualify_Trunk(int unit, bcm_field_entry_t entry, bcm_trunk_t data,
                     bcm_trunk_t mask, bcm_field_qualify_t qual)
{
    if (qual != bcmFieldQualifySrcTrunk&& qual != bcmFieldQualifyDstTrunk) {
        FP_ERR(("FP(unit %d) Error: _field_qualify_Trunk() only works with SrcTrunk or "
                "DstTrunk \n", unit));
        return (BCM_E_INTERNAL);
    }

    if (soc_property_get(unit, spn_TRUNK_EXTEND, 0)) {
        TRUNK_CHK_TGID128(unit, data);
    } else {
        TRUNK_CHK_TGID32(unit, data);
    }

    if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
        /* Trunk Bit (Tf) is not with Trunk/Port ID */
        data = data | (1 << SOC_TRUNK_BIT_POS(unit));
        mask = mask | (1 << SOC_TRUNK_BIT_POS(unit));
    } else {
        data = _FIELD_TRUNK_BIT_INSERT(unit, data);
        mask = _FIELD_TRUNK_BIT_INSERT(unit, mask);
    }

    if (bcmFieldQualifyDstTrunk == qual) {
        BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit,
            entry, qual, (uint32 *)&data, (uint32 *)&mask, 0));
    }

    return _field_qualify32(unit, entry, qual, data, mask);
}

/*
 * Function:
 *     _field_qualify_Trunk_get
 * Purpose:
 *     Get qualifiers  Trunk ID and mask. 
 *
 * Parameters:
 *     unit       - (IN)  BCM device number
 *     entry      - (IN)  Field entry to qualify on
 *     data       - (OUT) Trunk ID to qualify
 *     mask       - (OUT) Trunk mask to qualify
 *
 * Returns:
 *     BCM_E_XXX       
 */
STATIC int
_field_qualify_Trunk_get(int unit, 
                         bcm_field_entry_t entry, 
                         bcm_trunk_t *data,
                         bcm_trunk_t *mask, 
                         bcm_field_qualify_t qual)
{
    uint32    hw_data = 0;       /* HW buffer data.             */
    uint32    hw_mask = 0;       /* HW buffer mask.             */
    int       rv;                /* Operation return stauts.    */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask))  {
        return (BCM_E_PARAM);
    }

    if ((qual != bcmFieldQualifySrcTrunk) && (qual != bcmFieldQualifyDstTrunk)) {
        return (BCM_E_INTERNAL);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, qual,
                                           &hw_data, &hw_mask);
    BCM_IF_ERROR_RETURN(rv);

    if (qual == bcmFieldQualifyDstTrunk) {
        BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
            entry, qual, &hw_data, &hw_mask));
    }

    if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
        /* Trunk Bit (Tf) is not with Trunk/Port ID */
        *data = hw_data & ~(1 << SOC_TRUNK_BIT_POS(unit));
        *mask = hw_mask & ~(1 << SOC_TRUNK_BIT_POS(unit));
    } else {
        *data = _FIELD_TRUNK_BIT_RESET(unit, hw_data);
        *mask = _FIELD_TRUNK_BIT_RESET(unit, hw_mask);
    }
    return (BCM_E_NONE);
}
#undef _FIELD_TRUNK_BIT_INSERT
#undef _FIELD_TRUNK_BIT_RESET
/*
 * Function:
 *      _field_qualify_PortTgid
 *
 * Purpose:
 *      Helper function for PortTgid APIs
 *
 * Parameters:
 *      unit - BCM device number
 *      entry - Entry ID
 *      qual  - Qualifier field
 *      data  - Matching data
 *      mask  - Bit mask for data
 *
 * Returns:
 *     BCM_E_NONE     - BCM device number
 *     BCM_E_PARAM    - Qualifier not in group's Qset
 */
int
_field_qualify_PortTgid(int unit, bcm_field_entry_t entry,
                        int qual, bcm_port_t data, bcm_port_t mask)
{
    bcm_port_t          port;
    bcm_trunk_t         tgid;
    bcm_module_t        modid;
    int                 rv;

    if (BCM_GPORT_IS_SET(data)) {
        rv = _field_qualifier_gport_resolve(unit, data, mask, 
                                           &port, &modid, &tgid);
        BCM_IF_ERROR_RETURN(rv);
        if (BCM_TRUNK_INVALID != tgid) {
            if (qual == bcmFieldQualifySrcPortTgid) {
                qual = bcmFieldQualifySrcTrunk;
            } else {
                qual = bcmFieldQualifyDstTrunk;
            }
            return _field_qualify_Trunk(unit, entry, tgid, mask, qual);
        } else {
            if (qual == bcmFieldQualifySrcPortTgid) {
                qual = bcmFieldQualifySrcPort;
            } else {
                qual = bcmFieldQualifyDstPort;
            }
            return _field_qualify_Port(unit,entry, modid, 
                                       BCM_FIELD_EXACT_MATCH_MASK,
                                       port, mask, qual);
        }
    } else 
#ifdef BCM_TRX_SUPPORT
    if (SOC_IS_TRX(unit)) {
        return BCM_E_UNAVAIL;
    }
#endif

    return _field_qualify32(unit, entry, qual, data, mask);
}

/*
 * Function:
 *      _field_qualify_PortTgid_get
 *
 * Purpose:
 *      Helper function for PortTgid APIs
 *
 * Parameters:
 *      unit - BCM device number
 *      entry - Entry ID
 *      qual  - Qualifier field
 *      data  - Matching data
 *      mask  - Bit mask for data
 *
 * Returns:
 *     BCM_E_NONE     - BCM device number
 *     BCM_E_PARAM    - Qualifier not in group's Qset
 */
int
_field_qualify_PortTgid_get(int unit, bcm_field_entry_t entry,
                        int qual, bcm_port_t *data, bcm_port_t *mask)
{
    int isGport;             /* Port format is gport.       */
    int rv;                  /* Operation return status.    */  

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask))  {
        return (BCM_E_PARAM);
    }

    /* Check requested output format. */
    rv = bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport);
    BCM_IF_ERROR_RETURN(rv);

    if (isGport) {
        return (BCM_E_UNAVAIL);
    }
    
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, qual,
                                             (uint32 *)data, (uint32 *)mask);
}

/*
 * Function:
 *      _field_qualify_source_virtual_port
 *
 * Purpose:
 *      Utility routine to qualify MPLS/MIM Source Virtual Port.
 * Parameters:
 *      unit            - BCM device number
 *      entry           - Entry ID
 *      qual            - Qualifier field
 *      data            - Matching data
 *      mask            - Bit mask for data
 *      ingress_entity  - Ingress entity type selector status
 *
 * Returns:
 *     BCM_E_NONE     - BCM device number
 *     BCM_E_PARAM    - Qualifier not in group's Qset
 */

STATIC int
_field_qualify_source_virtual_port(int unit, bcm_field_entry_t entry,
                 int qual, uint32 data, uint32 mask, int ingress_entity)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t *f_ent;
    int rv;

    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

    if (q_offset->secondary)
    {
        f_ent->flags |= _FP_ENTRY_USES_IPBM_OVERLAY;
    }

    if (mask == (uint32)BCM_FIELD_EXACT_MATCH_MASK) {
        /* Exact match requested, make maximum mask value */
        mask =  (1 << q_offset->width) - 1;
    }

    if ((_BCM_FIELD_STAGE_EXTERNAL != f_ent->group->stage_id)
        && (0 == ingress_entity)) {
        /* Set SVP valid bit to TRUE */
        data |= (1 << (q_offset->width - 1));
    }

    /* Program data/mask pair to tcam buffer. */
    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    f_ent->flags |= _FP_ENTRY_DIRTY;
    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_qualify32
 *
 * Purpose:
 *      Utility routine for qualify APIs taking 32 bits or less
 *
 * Parameters:
 *      unit - BCM device number
 *      entry - Entry ID
 *      qual  - Qualifier field
 *      data  - Matching data
 *      mask  - Bit mask for data
 *
 * Returns:
 *     BCM_E_NONE     - BCM device number
 *     BCM_E_PARAM    - Qualifier not in group's Qset
 */

int
_field_qualify32(int unit, bcm_field_entry_t entry,
                 int qual, uint32 data, uint32 mask)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t           *f_ent;
    int                      rv;

    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

    if (q_offset->secondary)
    {
        f_ent->flags |= _FP_ENTRY_USES_IPBM_OVERLAY;
    }

    if (mask == (uint32)BCM_FIELD_EXACT_MATCH_MASK) {
        /* Exact match requested, make maximum mask value */
        mask = (32 == q_offset->width)
            ? ~0 : (1 << (q_offset->width + q_offset->width1 + q_offset->width2)) - 1;
    }

    /* Program data/mask pair to tcam buffer. */
    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    f_ent->flags |= _FP_ENTRY_DIRTY;
    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_qualify_ip6_get
 * 
 * Purpose:
 *      Utility routine to extract qualifier IPv6 data and mask.
 *
 * Parameters:
 *     unit   - (IN) BCM device number
 *     entry  - (IN) BCM field entry id.
 *     qual   - (IN) Qualifier id. 
 *     flags  - (IN) Part of IPv6 address specification.
 *     data   - (OUT) Qualifier data. 
 *     mask   - (OUT) Qualifier mask. 
 * Returns:
 *     BCM_E_XXX
 */

int
_field_qualify_ip6_get(int unit, bcm_field_entry_t entry,
                   bcm_field_qualify_t qual, 
                   bcm_ip6_t *data, bcm_ip6_t *mask)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t           *f_ent;
    uint32                   ref_data[_FP_QUAL_DATA_WORDS]; 
    uint32                   ref_mask[_FP_QUAL_DATA_WORDS];
    uint8                    ref_offset; 
    int                      rv;

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    /* Initialization. */
    sal_memset(ref_data, 0, 4 * sizeof(uint32)); 
    sal_memset(ref_mask, 0, 4 * sizeof(uint32)); 
    switch(qual) {
      case bcmFieldQualifySrcIp6High:
      case bcmFieldQualifyDstIp6High:
      case bcmFieldQualifyInnerSrcIp6High:
      case bcmFieldQualifyInnerDstIp6High:
          ref_offset = 2;
          break;
      default:
          ref_offset = 0;
    }

    /* Get field entry part that contains qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual, &q_offset);
    BCM_IF_ERROR_RETURN(rv);


    /* Read qualifier match value and mask. */
    rv = _bcm_field_qual_value_get(unit, q_offset, f_ent, 
                                   ref_data + ref_offset, 
                                   ref_mask + ref_offset);
    BCM_IF_ERROR_RETURN(rv);

    SAL_IP6_ADDR_FROM_UINT32((*data), ref_data);
    SAL_IP6_ADDR_FROM_UINT32((*mask), ref_mask);

    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_qualify_ip6
 * 
 * Purpose:
 *      Utility routine for qualify APIs taking IPv6 data and mask.
 *
 * Parameters:
 *     unit   - (IN) BCM device number
 *     entry  - (IN) BCM field entry id.
 *     qual   - (IN) Qualifier id. 
 *     data   - (IN) Qualifier data. 
 *     mask   - (IN) Qualifier mask. 
 * Returns:
 *     BCM_E_XXX
 */

int
_field_qualify_ip6(int unit, bcm_field_entry_t entry,
                   bcm_field_qualify_t qual, 
                   bcm_ip6_t data, bcm_ip6_t mask)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t           *f_ent;
    uint32                   ref_data[_FP_QUAL_DATA_WORDS]; 
    uint32                   ref_mask[_FP_QUAL_DATA_WORDS];
    uint8                    ref_offset; 
    int                      rv;

    FP_VVERB(("_field_qualify_ip6\n"));

    /* Initialization. */
    switch(qual) {
      case bcmFieldQualifySrcIp6High:
      case bcmFieldQualifyDstIp6High:
      case bcmFieldQualifyInnerSrcIp6High:
      case bcmFieldQualifyInnerDstIp6High:
          ref_offset = 2;
          break;
      default:
          ref_offset = 0;
    }

    /* Get field entry part that contains qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

    SAL_IP6_ADDR_TO_UINT32(data, ref_data);
    SAL_IP6_ADDR_TO_UINT32(mask, ref_mask);

    /* Program data/mask pair to tcam buffer. */
    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, 
                                   ref_data + ref_offset, 
                                   ref_mask + ref_offset);
    BCM_IF_ERROR_RETURN(rv);

    f_ent->flags |= _FP_ENTRY_DIRTY;
    return (BCM_E_NONE);
} 

/*
 * Function:
 *      _field_qualify_L2PayloadFirstEightBytes_get
 * 
 * Purpose:
 *      Utility routine to extract qualifier L2PayloadFirstEightBytes 
 *      data and mask.
 *
 * Parameters:
 *     unit   - (IN) BCM device number
 *     entry  - (IN) BCM field entry id.
 *     qual   - (IN) Qualifier id. 
 *     data1   - (OUT) Qualifier first four bytes of match data. 
 *     data2   - (OUT) Qualifier last four bytes of match data. 
 *     mask1   - (OUT) Qualifier first four bytes of match mask. 
 *     mask2   - (OUT) Qualifier last four bytes of match mask. 
 * Returns:
 *     BCM_E_XXX
 */

int
_field_qualify_L2PayloadFirstEightBytes_get(int unit, 
                                            bcm_field_entry_t entry,
                                            bcm_field_qualify_t qual, 
                                            uint32 *data1, uint32 *data2, 
                                            uint32 *mask1, uint32 *mask2)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t           *f_ent;
    uint32                   ref_data[_FP_QUAL_DATA_WORDS]; 
    uint32                   ref_mask[_FP_QUAL_DATA_WORDS];
    int                      rv;

    /* Input parameters check. */
    if ((NULL == data1) || (NULL == data2) ||
        (NULL == mask1) || (NULL == mask2)) {
        return (BCM_E_PARAM);
    }

    /* Get field entry part that contains qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

    /* Read qualifier match value and mask. */
    rv = _bcm_field_qual_value_get(unit, q_offset, f_ent, ref_data,
                                   ref_mask);
    BCM_IF_ERROR_RETURN(rv);
    
    _FP_UNPACK_L2_EIGHT_BYTES_PAYLOAD(ref_data, data1, data2);
    _FP_UNPACK_L2_EIGHT_BYTES_PAYLOAD(ref_mask, mask1, mask2);

    return (BCM_E_NONE);
}

/*
 * Function:
 *      _field_qualify_L2PayloadFirstEightBytes
 *
 * Purpose:
 *      Utility routine for qualify L2PayloadFirstEightBytes 
 *      data and mask.
 * 
 * Parameters:
 *     unit   - (IN) BCM device number
 *     entry  - (IN) BCM field entry id.
 *     qual   - (IN) Qualifier id. 
 *     data1  - (IN) Qualifier first four bytes of match data.
 *     data2  - (IN) Qualifier last four bytes of match data.
 *     mask1  - (IN) Qualifier first four bytes of match mask.
 *     mask2  - (IN) Qualifier last four bytes of match mask.
 *
 * Returns:
 *     BCM_E_XXX
 */

int
_field_qualify_L2PayloadFirstEightBytes(int unit, 
                                        bcm_field_entry_t entry,
                                        bcm_field_qualify_t qual, 
                                        uint32 data1, uint32 data2,
                                        uint32 mask1, uint32 mask2)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t           *f_ent;
    uint32                   ref_data[_FP_QUAL_DATA_WORDS]; 
    uint32                   ref_mask[_FP_QUAL_DATA_WORDS];
    int                      rv;

    FP_VVERB(("_field_qualify_L2PayloadFirstEightBytes\n"));

    /* Get field entry part that contains qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

    sal_memset(&ref_data, 0, sizeof(ref_data));
    sal_memset(&ref_mask, 0, sizeof(ref_mask));

    _FP_PACK_L2_EIGHT_BYTES_PAYLOAD(data1, data2, ref_data);
    _FP_PACK_L2_EIGHT_BYTES_PAYLOAD(mask1, mask2, ref_mask);

    /* Program data/mask pair to tcam buffer. */
    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, ref_data,
                                   ref_mask);
    BCM_IF_ERROR_RETURN(rv);

    f_ent->flags |= _FP_ENTRY_DIRTY;
    return (BCM_E_NONE);
}

/*
 * Function: _field_udf_create_id
 * 
 * Purpose:
 *     Configure a virtual UDF, using the designated udf_id.
 *
 * Parameters:
 *     unit      - BCM device number
 *     udf_spec  - Pointer to a user-defined field (UDF) definition structure
 *     udf_id    - UDF ID
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_udf_create_id(int unit, bcm_field_udf_spec_t *udf_spec,
                            bcm_field_udf_t udf_id)
{
    _field_control_t    *fc;
    int                 rv = BCM_E_UNAVAIL;

    if (udf_spec == NULL ||  (udf_id >= BCM_FIELD_USER_NUM_UDFS)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    if (fc->udf[udf_id].valid) {
        bcm_field_udf_spec_t *current_udf_spec;
        current_udf_spec = sal_alloc(sizeof(bcm_field_udf_spec_t), "UDF spec");
        if (NULL == current_udf_spec) {
            return (BCM_E_MEMORY);
        }
        sal_memset(current_udf_spec, 0, sizeof(bcm_field_udf_spec_t));

        rv = fc->functions.fp_udf_read(unit, current_udf_spec,
                                       fc->udf[udf_id].udf_num, 
                                       fc->udf[udf_id].user_num); 
        if (BCM_FAILURE(rv)) {
            sal_free(current_udf_spec);
            return rv;
        }
        else if (0 == sal_memcmp(udf_spec, current_udf_spec, 
                             sizeof(bcm_field_udf_spec_t))) {
            /* UDF already configured as requested */
            sal_free(current_udf_spec);
            return (BCM_E_NONE);
        }
        else {
            /* UDF already configured, but differently */
            sal_free(current_udf_spec);
            return (BCM_E_EXISTS);
        }
    }

    /* UDF is currently unused; go ahead and take it */
    rv = fc->functions.fp_udf_write(unit, udf_spec, 
                                    fc->udf[udf_id].udf_num, 
                                    fc->udf[udf_id].user_num); 
    if (BCM_FAILURE(rv)) {
        return rv;
    }

    fc->udf[udf_id].valid = 1;
    fc->udf[udf_id].use_count = 0;

    return (BCM_E_NONE);
}

/*
 * Function: _field_udf_create
 *
 * Purpose:
 *     Create a virtual UDF identifier, based on the requested udf_spec.
 *     On success, returns a udf_id.
 *
 * Parameters:
 *     unit      - BCM device number
 *     udf_spec  - Pointer to a user-defined field (UDF) definition structure
 *     udf_id    - Pointer to a UDF ID
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_udf_create(int unit, bcm_field_udf_spec_t *udf_spec,
                  bcm_field_udf_t *udf_id)
{
    _field_control_t    *fc;
    bcm_field_udf_t     tuid, free_udf_id;
    int                 rv;

    if (udf_spec == NULL || udf_id == NULL) {
        return (BCM_E_PARAM);
    }
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* First check for any currently configured UDFs to share */
    free_udf_id = BCM_FIELD_USER_NUM_UDFS;
    for (tuid = 0; tuid < BCM_FIELD_USER_NUM_UDFS; tuid++) {
        if (!fc->udf[tuid].valid) {
            if (BCM_FIELD_USER_NUM_UDFS == free_udf_id) {
                free_udf_id = tuid;
            }
            continue;
        }
        rv = _field_udf_create_id(unit, udf_spec, tuid);
        if (BCM_SUCCESS(rv)) {
            *udf_id = tuid;
            return (BCM_E_NONE);
        }
        else if (rv != BCM_E_EXISTS) {
            return rv;
        }
    }

    /* No UDFs to share; available UDF? */
    if (BCM_FIELD_USER_NUM_UDFS == free_udf_id) {
        rv = BCM_E_RESOURCE;
    }
    else {
        *udf_id = free_udf_id;
        rv = _field_udf_create_id(unit, udf_spec, *udf_id);
    }
    return rv;
}

/*
 * Function:
 *     _field_entry_shift_down
 * Purpose:
 *     
 * Parameters:
 *     unit     - BCM device number
 *     target_fs - slice where the entry in prio_set should go
 *     target_index - corresponding index
 *     next_null_fs - slice which contains a NULL entry after target_index
 *     next_null_index - corresponding index
 * Returns:
 *     BCM_E_NONE   - Success
 */
STATIC int
_field_entry_shift_down(int unit, _field_group_t *fg, 
                        _field_slice_t *target_fs, uint16 target_index,
                        _field_slice_t *next_null_fs, uint16 next_null_index)
{
    uint16              slice_idx_empty;
    _field_stage_t      *stage_fc;
    int                 slice_sz;
    int                 tmp_idx1;
    int                 tmp_idx2;
    _field_slice_t      *fs;
    int                 rv;

    /* Input parameter check. */
    if ((NULL == target_fs) || (NULL == fg) || (NULL == next_null_fs))  {
        return (BCM_E_PARAM);
    } 

    BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, target_fs->stage_id, 
                                                 &stage_fc));

    slice_idx_empty = next_null_index;
    fs = next_null_fs;

    /*
     * Move entries one step down
     *     starting from the last entry
     * IDEA: 
     *     when in different slices, target_fs != fs
     *     when in same slice, move till slice_idx_empty > target_index  
     */
    while ((slice_idx_empty > target_index) || (target_fs != fs)) {
        /* Move the entry at the previous index to the empty index. */
        if (slice_idx_empty == 0) {
            /* Get number of entries in slice. */
            _BCM_FIELD_ENTRIES_IN_SLICE(fg, fs->prev, slice_sz);

            /* Get higher slice first entry tcam index. */
            rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc, 
                                                     fs->slice_number, 0, 
                                                     &tmp_idx1);
            BCM_IF_ERROR_RETURN(rv);

            /* Get lower slice last entry tcam index. */
            rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc, 
                                                     fs->prev->slice_number, 
                                                     slice_sz - 1, &tmp_idx2);
            BCM_IF_ERROR_RETURN(rv);

            /* Perform entry move. */
            rv = _field_entry_move(unit, fs->prev->entries[slice_sz-1], 
                                   (tmp_idx1 - tmp_idx2));
            BCM_IF_ERROR_RETURN(rv);

            slice_idx_empty = slice_sz - 1;
            fs = fs->prev;
        } else {
            /* Get higher entry tcam index. */
            rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc,
                                                     fs->slice_number,
                                                     slice_idx_empty,
                                                     &tmp_idx1);
            BCM_IF_ERROR_RETURN(rv);

            /* Get lower entry tcam index. */
            rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc,
                                                     fs->slice_number,
                                                     slice_idx_empty - 1,
                                                     &tmp_idx2);
            BCM_IF_ERROR_RETURN(rv);

            /* Perform entry move. */
            rv = _field_entry_move(unit, fs->entries[slice_idx_empty - 1], 
                                   (tmp_idx1 - tmp_idx2));
            BCM_IF_ERROR_RETURN(rv);

            slice_idx_empty--;
        }
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_entry_shift_up
 * Purpose:
 *     
 * Parameters:
 *     unit     - BCM device number
 *     target_fs - slice where the entry in prio_set should go
 *     target_index - corresponding index
 *     prev_null_fs - slice which contains a NULL entry before target_index
 *     prev_null_index - corresponding index
 * Returns:
 *     BCM_E_NONE   - Success
 */
STATIC int
_field_entry_shift_up(int unit, _field_group_t *fg, 
                      _field_slice_t *target_fs, uint16 target_index,
                      _field_slice_t *prev_null_fs, uint16 prev_null_index)
{
    uint16              slice_idx_empty;
    _field_stage_t      *stage_fc;
    int                 slice_sz;        
    int                 tmp_idx1;
    int                 tmp_idx2;
    _field_slice_t      *fs;
    int                 rv;

    /* Input parameter check. */
    if ((NULL == target_fs) || (NULL == fg) || (NULL == prev_null_fs))  {
        return (BCM_E_PARAM);
    } 

    BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, target_fs->stage_id, 
                                                 &stage_fc));

    slice_idx_empty = prev_null_index;
    fs = prev_null_fs;

    while ((slice_idx_empty < target_index) || (fs != target_fs)) {
        /* Move the entry at the next index to the prev. empty index. */
        _BCM_FIELD_ENTRIES_IN_SLICE(fg, fs, slice_sz);
        if (slice_idx_empty == (slice_sz - 1)) {
            /* Get lower slice last entry tcam index. */
            rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc,
                                                     fs->slice_number,
                                                     slice_sz - 1, &tmp_idx1);
            BCM_IF_ERROR_RETURN(rv);

            /* Get upper slice first entry tcam index. */
            rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc,
                                                     fs->next->slice_number,
                                                     0, &tmp_idx2);
            BCM_IF_ERROR_RETURN(rv);

            /* Perform entry move. */
            rv = _field_entry_move(unit, fs->next->entries[0], 
                                   (tmp_idx1 - tmp_idx2));
            BCM_IF_ERROR_RETURN(rv);

            fs = fs->next;
            slice_idx_empty = 0;
        } else {
            /* Get lower entry tcam index. */
            rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc, 
                                                     fs->slice_number, 
                                                     slice_idx_empty, 
                                                     &tmp_idx1);
            BCM_IF_ERROR_RETURN(rv);

            /* Get higher entry tcam index. */
            rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc, 
                                                     fs->slice_number, 
                                                     slice_idx_empty + 1, 
                                                     &tmp_idx2);
            BCM_IF_ERROR_RETURN(rv);

            /* Perform entry move. */
            rv = _field_entry_move(unit, fs->entries[slice_idx_empty + 1], 
                                   (tmp_idx1 - tmp_idx2));
            BCM_IF_ERROR_RETURN(rv);

            slice_idx_empty++;
        }
    }

    return (BCM_E_NONE);
}

/*
 * Function: _field_entry_prio_set
 *
 * Purpose:
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Field entry to operate on
 *
 * Returns:
 *     BCM_E_NONE       Success
 *
 * Notes: 
 *     The earlier checks guarantee that there is a free slot somewhere
 *     i.e. in one of the alloted slices for the group.
 */
STATIC int
_field_entry_prio_set(int unit, bcm_field_entry_t entry, int prio)
{
    int                 slice_idx_target = 0;
    int                 temp;
    int                 temp1;
    int                 slice_idx_old;
    int                 idx;
    _field_control_t    *fc;
    _field_group_t      *fg;
    _field_slice_t      *fs;
    _field_stage_t      *stage_fc;
    _field_entry_t      *f_ent;
    int parts_count;
    int rv;
    int slice_sz;   
    _field_slice_t  *prev_null_fs = NULL; 
                        /* The last NULL entry b4 target loc */
    _field_slice_t  *target_fs = NULL; 
                        /* The target slice */
    _field_slice_t  *next_null_fs = NULL; 
                        /* The next NULL entry after target loc */
    uint16 prev_null_index = 0; 
    uint16 next_null_index = 0;
    int dir = -1; /* Direction of shift: -1 = UP, 1 = DOWN */
    int decr_on_shift_up = TRUE;
    int flag_no_free_entries = FALSE;
    
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    rv = _bcm_field_entry_get_by_id(unit, entry, &f_ent);
    if (BCM_FAILURE(rv)) {
        return (rv);
    }

    /* If the priority isn't changing, just return.*/
    if (f_ent->prio == prio) {
        return (BCM_E_NONE);
    }
    
    fg = f_ent->group;
    fs = f_ent->fs;

    if (fg->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        rv = fc->functions.fp_external_entry_prio_set(unit, f_ent, prio);
        return (rv);
    }

    prio_set_with_no_free_entries = FALSE; /* Global variable */
    
    /* Get stage control structure. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        return (rv);
    }

    /* Get number of entry parts we have to read. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* 
     * If priority is changing, but still in proper place, 
     * just goto end (change the f_ent->prio to prio)
     */
    if (_field_reqd_prio_set_move(unit, f_ent, prio) == FALSE) {
        goto end;
    }

    _BCM_FIELD_ENTRIES_IN_SLICE(fg, fs, slice_sz);

    slice_idx_old = f_ent->slice_idx;
    if (slice_idx_old >= slice_sz) {
        return (BCM_E_INTERNAL);
    }

    if (_field_no_free_entries(unit, fg) == TRUE) {
        if (!(f_ent->flags & _FP_ENTRY_INSTALLED)) {
            /*
             * As there are no free entries in any of the slices belonging to
             * this group, and this entry is NOT installed,
             *     fake that it does not exist.
             */
            f_ent->fs->entries[f_ent->slice_idx] = NULL;
            flag_no_free_entries = TRUE;
        } else {
            return BCM_E_CONFIG;
        }
    }
    
    /* Find the target slice index. That is the one with the highest index
     * for this priority class. */
    fs = &fg->slices[0];
    while (fs != NULL) {
        _BCM_FIELD_ENTRIES_IN_SLICE(fg, fs, slice_sz);
        for (slice_idx_target = 0;
             slice_idx_target < slice_sz;
             slice_idx_target++) {

            /* Skip the f_ent itself */
            if (f_ent == fs->entries[slice_idx_target]) {
                continue;
            }
            if (fs->entries[slice_idx_target] == NULL) {
                prev_null_fs = fs;
                prev_null_index = slice_idx_target;
                continue;
            }
            if (_field_entry_prio_cmp(prio, fs->entries[slice_idx_target]->prio)
                > 0) {
                FP_VVERB(("FP(unit %d) vverb: Found target slice_idx=%d\n", 
                          unit, slice_idx_target));
                target_fs = fs;
                break;
            }

        }
        if (slice_idx_target < slice_sz) {
            break;
        }
        fs = fs->next;
    }
    temp = slice_idx_target;
    while (fs != NULL) {
        _BCM_FIELD_ENTRIES_IN_SLICE(fg, fs, slice_sz);
        for (; temp < slice_sz; temp++) {
            if (fs->entries[temp] == NULL) {
                next_null_fs = fs;
                next_null_index = temp;
                break;
            }
        }
        if (next_null_fs != NULL) {
            break;
        }
        fs = fs->next;
        temp = 0;
    }

    /* 
     * Put the entry back, 
     *     in case there is a context switch, AND
     *     another thread calls entry_create
     */
    if (flag_no_free_entries == TRUE) {
        f_ent->fs->entries[f_ent->slice_idx] = f_ent;
    }
    
    if ((prev_null_fs == NULL) && (next_null_fs == NULL)) {
        return BCM_E_CONFIG; /* No free entries to move */
    }

    if (target_fs == NULL) {
        /*
         * target_fs will be NULL when the target location is after
         * the last entry in slice.
         * Now,
         *   1. There may be NULL entries after last entry
         *       Insert entry there
         *   2. The last entry is at last location in (last) slice
         *       Need to do a shift_up to free-up the last location.
         */
/*
 *  Case 1: 
 *  |-------------|
 *  |       6     |
 *  |-------------|
 *  |       5     |
 *  |-------------|
 *  |       4     |<--- change priority to 1
 *  |-------------| 
 *  |       3     |
 *  |-------------|
 *  |       2     |
 *  |-------------|
 *  |     .       |
 *  |NULL .entries|
 *  |     .       |
 *  |-------------|
 *
 *  becomes                  |-------------|
 *                           |       6     |
 *                           |-------------|
 *                           |       5     |
 *                           |-------------|
 *                           |    NULL     |
 *                           |-------------| 
 *                           |       3     |
 *                           |-------------|
 *                           |       2     |
 *                           |-------------|
 *                           |     .       |
 *                           |NULL .entries|
 *                           |     1       |<--- comes to the end.
 *                           |-------------|
 *  
 *  Case 2:
 *  |-------------|
 *  |     .       |
 *  |NULL .entries|
 *  |     .       |
 *  |-------------|
 *  |       6     |
 *  |-------------|
 *  |       5     |
 *  |-------------|
 *  |       4     |<--- change priority to 1
 *  |-------------| 
 *  |       3     |
 *  |-------------|
 *  |       2     |
 *  |-------------|
 *
 *  becomes                  |-------------|
 *                           |     .       |
 *                           |NULL .entries|
 *                           |       6     |
 *                           |-------------|
 *                           |       5     |
 *                           |-------------|
 *                           |     NULL    |
 *                           |-------------|
 *                           |       3     |
 *                           |-------------| 
 *                           |       2     |
 *                           |-------------|
 *                           |       1     |<--- comes to the end,
 *                           |-------------|           others shift UP
 *  
 */
        fs = &fg->slices[0];
        while (fs->next != NULL) {
            fs = fs->next;
        }
        _BCM_FIELD_ENTRIES_IN_SLICE(fg, fs, slice_sz);
        if ((fs == prev_null_fs) && 
            (prev_null_index == slice_sz - 1)) {
            target_fs = prev_null_fs;
            slice_idx_target = prev_null_index;
            goto only_move;
        } else {
            target_fs = fs;
            slice_idx_target = slice_sz - 1;
            decr_on_shift_up = FALSE;
        }
    }
        
    
    /*
     * Check if the movement is feasible
     * If group spans across slices, need to verify that
     * entries moving across slices do not have shared meters, counters
     * AND that new slice has meter, counter available, if required
     */
    if (_field_validate_prio_set(unit, fg, f_ent, 
                                 prev_null_index, prev_null_fs,
                                 slice_idx_target, target_fs,
                                 next_null_index, next_null_fs,
                                 &dir) == FALSE) {
        return (BCM_E_PARAM);
    }

    if (dir == 1) {
        /* 
         * Move the entry at the target index to target_index+1. This may
         * mean shifting more entries down to make room. In other words,
         * shift the target index and any that follow it down 1 as far as the
         * next empty index.
         */
        if (target_fs->entries[slice_idx_target] != NULL) {
            rv = _field_entry_shift_down(unit, fg,
                                         target_fs, slice_idx_target,
                                         next_null_fs, next_null_index);
            BCM_IF_ERROR_RETURN(rv);
        }
    } else {
        /*
         * Similar thing for Shifting UP
         *     Depends on if this falls into Case-2 in the fig. above.
         */
        if (decr_on_shift_up == TRUE) {
            slice_idx_target--;
            if (slice_idx_target == -1) {
                _BCM_FIELD_ENTRIES_IN_SLICE(fg, target_fs, slice_sz);
                slice_idx_target = slice_sz - 1;
                target_fs = target_fs->prev;
            }
        }
        if (target_fs->entries[slice_idx_target] != NULL) {
            rv = _field_entry_shift_up(unit, fg, 
                                       target_fs, slice_idx_target, 
                                       prev_null_fs, prev_null_index);
            BCM_IF_ERROR_RETURN(rv);
        }
    }
    
    /* Move the entry from its old slice index to the target slice index. */
only_move: 
    rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc, 
                                             target_fs->slice_number,
                                             slice_idx_target, &temp);
    BCM_IF_ERROR_RETURN(rv);

    rv = _bcm_field_slice_offset_to_tcam_idx(unit, stage_fc, 
                                             f_ent->fs->slice_number, 
                                             f_ent->slice_idx, &temp1);
    BCM_IF_ERROR_RETURN(rv);

    if ((temp - temp1) != 0) {
        if (flag_no_free_entries) {
            prio_set_with_no_free_entries = TRUE;
        }

        rv = _field_entry_move(unit, f_ent, (temp - temp1));
        if (BCM_FAILURE(rv)) {
            prio_set_with_no_free_entries = FALSE; 
            return rv;
        }

        /* in case _field_entry_move is called from some other function */
        prio_set_with_no_free_entries = FALSE; 
    }
       
end:    
    /* Assign the requested priority to the entry. */
    for (idx = 0; idx < parts_count; idx++) {
        f_ent[idx].prio = prio;
    }

    if (fg->group_status.prio_max < prio) {
        fg->group_status.prio_max = prio;
    }
    if (0 <= prio &&
        (prio < fg->group_status.prio_min || fg->group_status.prio_min < 0)) {
        fg->group_status.prio_min = prio;
    }

    return (BCM_E_NONE);
}

#ifdef BCM_WARM_BOOT_SUPPORT
int _field_table_read(int unit, soc_mem_t mem, char **buffer_p,
    const char *buffer_name_p)
{
    int index_min;
    int index_max;
    int rv;

    *buffer_p = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, mem),
        buffer_name_p);

    if (*buffer_p == NULL)
    {
        return BCM_E_MEMORY;
    }

    index_min = soc_mem_index_min(unit, mem);
    index_max = soc_mem_index_max(unit, mem);

    rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, index_min, index_max,
        *buffer_p);

    return rv;
}
#endif /* BCM_WARM_BOOT_SUPPORT */

/*
 * Function: _field_entry_qualifiers_init
 *
 * Purpose:
 *     Initialize entry qualifiers based on a group qset.
 *
 * Parameters:
 *     unit -  (IN) BCM device number.
 *     f_ent - (IN/OUT) Field entry structure.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_entry_qualifiers_init(int unit, _field_entry_t *f_ent)
{
    int                 count;        /* Number of ports.             */ 
    bcm_port_t          port;         /* Port iterator.               */ 
    _field_group_t      *fg;          /* Field group info.            */
    int                 rv;           /* Operation return status.     */
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    int                 parts_count;  /* Field entry parts count.     */
    int                 idx;          /* Parts iteration index.       */
    _field_control_t    *fc;          /* Field control structure.     */
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    bcm_port_config_t  port_config;   /* Device port config structure.*/


    fg = f_ent->group;

    /* Read device port configuration. */ 
    BCM_IF_ERROR_RETURN(bcm_esw_port_config_get(unit, &port_config));

    /*
     * If the group has bcmFieldQualifyInPorts in its Qset, qualify the entry
     * on the group's port bitmap.
     */
    if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyInPorts)) {
        rv = bcm_esw_field_qualify_InPorts(unit, f_ent->eid, fg->pbmp,
                                           port_config.all);
        BCM_IF_ERROR_RETURN(rv);
    }

    /*
     * If the group has bcmFieldQualifyOutPorts in its Qset, qualify the entry
     * on the group's port bitmap.
     */
    if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyOutPorts)) {
        rv = bcm_esw_field_qualify_OutPorts(unit, f_ent->eid, fg->pbmp,
                                            port_config.all);
        BCM_IF_ERROR_RETURN(rv);
    }

    /*
     * If the group has bcmFieldQualifyInPort in its Qset, and there is only
     * one port in the group's pbmp, then qualify on that port.
     */
    if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyInPort)) {
        BCM_PBMP_COUNT(fg->pbmp, count);
        if (count == 1) {
            BCM_PBMP_ITER(fg->pbmp, port) {
                rv = bcm_esw_field_qualify_InPort(unit, f_ent->eid, port,
                                                  BCM_FIELD_EXACT_MATCH_MASK);
                BCM_IF_ERROR_RETURN(rv);
            }
        }
    }

    /*
     *  If the group has bcmFieldQualifyIp4/6 in Qset add IpType 
     * default value to the entry. 
     */
    if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyIp4) &&
        (fg->stage_id != _BCM_FIELD_STAGE_EXTERNAL)) {
        rv = bcm_esw_field_qualify_IpType(unit, f_ent->eid, bcmFieldIpTypeIpv4Any);
        BCM_IF_ERROR_RETURN(rv);
    }

    if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyIp6) &&
        (fg->stage_id != _BCM_FIELD_STAGE_EXTERNAL)) {
        rv = bcm_esw_field_qualify_IpType(unit, f_ent->eid, bcmFieldIpTypeIpv6);
        BCM_IF_ERROR_RETURN(rv);
    }

    /*
     *  Set key match type for egress FP.
     */
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (_BCM_FIELD_STAGE_EGRESS == fg->stage_id) {
        /* Get field control structure. */
        BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

        /* Get number of parts in field entry based on group flags. */
        rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
        BCM_IF_ERROR_RETURN(rv);

        for (idx = 0; idx < parts_count; idx++) {
            rv = fc->functions.fp_egress_key_match_type_set(unit, f_ent + idx);
            BCM_IF_ERROR_RETURN(rv);
        } 
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT  */

    return (BCM_E_NONE);
}

/*
 * Function: _field_entry_create_id
 *
 * Purpose:
 *     Create a blank entry group based on a group;
 *     allows selection of a specific slot in a slice
 *
 * Parameters:
 *     unit -  (IN) BCM device number.
 *     group - (IN) Field group ID.
 *     entry - (IN) Requested entry ID; must be in the range prio_min through
 *             prio_max as returned by bcm_field_group_status_get().
 * Returns:
 *     BCM_E_INIT      - unit not initialized
 *     BCM_E_EXISTS    - Entry ID already in use
 *     BCM_E_NOT_FOUND - Group ID not found in unit
 *     BCM_E_MEMORY    - allocation failure
 *     BCM_E_NONE      - Success
 */
STATIC int
_field_entry_create_id(int unit, bcm_field_group_t group,
                       bcm_field_entry_t entry)
{
    _field_stage_t      *stage_fc;    /* Stage field control info.    */
    _field_group_t      *fg;          /* Field group info.            */
    _field_slice_t      *fs_pri;      /* Primary slice pointer.       */
    _field_entry_t      *f_ent;       /* Allocated entry buffer.      */
    int                 rv;           /* Operation return status.     */

    FP_VVERB(("FP(unit %d) vverb: bcm_esw_field_entry_create_id(group=%d, entry=%d)\n",
              unit, group, entry));

    /* Confirm that 'entry' is not already used on unit */
    if (BCM_SUCCESS(_field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent))) {
        FP_ERR(("FP(unit %d) Error: entry=(%d) already exists.\n", unit, entry));
        return (BCM_E_EXISTS);
    }

    /* Get group control structure. */
    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_ERR(("FP(unit %d) Error: group=(%d) group get failure.\n", unit, group));
        return (rv);
    }


    /* Get group stage control structure. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_ERR(("FP(unit %d) Error: Stage (%d) control get failure.\n", 
                unit, fg->stage_id));
        return (rv);
    }

    /* Reserve a slice with room for new entry. */ 
    rv = _field_group_slice_entry_reserve(unit, fg, &fs_pri);
    if (BCM_FAILURE(rv)) {
        FP_ERR(("FP(unit %d) Error: Group (%d) no room.\n", unit, group));
        return (rv);
    }

    /* Create entry in primary slice. */
    rv = _field_entry_phys_create(unit, stage_fc, entry, 
                                  BCM_FIELD_ENTRY_PRIO_LOWEST, 
                                  fs_pri, fg, &f_ent);
    if (BCM_FAILURE(rv)) {
        return (rv);
    }

    /* Initialize entry qualifiers based on group qset. */
    rv = _field_entry_qualifiers_init(unit, f_ent);
    if (BCM_FAILURE(rv)) {
        _field_entry_phys_destroy(unit, f_ent);
        return (rv);
    }
    return (BCM_E_NONE);
}

/* Function    : _field_tpid_hw_decode
 * Description : Encode tpid value to hw specific value.
 * Parameters  : (IN) unit   BCM driver unit
 *               (IN) hw_code HW code. 
 *               (OUT) tpid  decoded TPID 
 * Returns     : BCM_E_XXX
 */
int
_field_tpid_hw_decode(int unit, uint32 hw_code, uint16 *tpid)
{
    switch (hw_code) {
      case 0x0:
          *tpid = 0x8100;
          break;
      case 0x1: 
          *tpid = 0x9100;
          break;
      case 0x2: 
          *tpid = 0x88a8;
          break;
      default:
          return (BCM_E_UNAVAIL);
    }
    return (BCM_E_NONE);
}

/* Function    : _bcm_field_tpid_hw_encode
 * Description : Encode tpid value to hw specific value.
 * Parameters  : (IN) unit   BCM driver unit
 *               (IN) tpid   TPID to encode
 *               (OUT) hw_code HW code. 
 * Returns     : BCM_E_XXX
 */
int
_bcm_field_tpid_hw_encode(int unit, uint16 tpid, uint32 *hw_code)
{
    switch (tpid) {
      case 0x8100:
          *hw_code = 0x00;
          break;
      case 0x9100:
          *hw_code = 0x01;
          break;
      case 0x88a8:
          *hw_code = 0x02;
          break;
      default:
          *hw_code = 0x03;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_action_alloc
 * Purpose:
 *     Allocate and initialize an action structure.
 * Parameters:
 *     unit     - BCM device number.
 *     action   - Action to perform (bcmFieldActionXXX)
 *     param0   - Action parameter (use 0 if not required)
 *     param1   - Action parameter (use 0 if not required)
 *     param2   - Action parameter (use 0 if not required)
 *     param3   - Action parameter (use 0 if not required)
 *     fa (OUT) - pointer to field action structure
 * Returns:
 *     BCM_E_MEMORY - allocation failure
 *     BCM_E_NONE   - Success
 */
int
_field_action_alloc(int unit, bcm_field_action_t action, 
                    uint32 param0, uint32 param1, uint32 param2, 
                    uint32 param3, _field_action_t **fa)
{
    *fa = sal_alloc(sizeof (_field_action_t), "field_action");
    if (*fa == NULL) {
        FP_ERR(("FP(unit %d) Error: allocation failure for field_action\n", unit));
        return (BCM_E_MEMORY);
    }
    sal_memset(*fa, 0, sizeof (_field_action_t));

    (*fa)->action = action;
    (*fa)->param[0] = param0;
    (*fa)->param[1] = param1;
    (*fa)->param[2] = param2;
    (*fa)->param[3] = param3;
    (*fa)->hw_index = _FP_INVALID_INDEX;
    (*fa)->old_index = _FP_INVALID_INDEX;
    /* mark new action as not yet installed */  
    (*fa)->flags |= (_FP_ACTION_VALID | _FP_ACTION_DIRTY); 


    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_action_meter_config
 * Purpose:
 *     Set meter mode.
 * Parameters:
 *     unit     - (IN) BCM device number. 
 *     f_ent    - (IN) Entry meter belongs to.
 *     param0   - (IN) Meter mode.
 *     param1   - (IN) Committed/Peak selector.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_action_meter_config(int unit, _field_entry_t *f_ent,  
                           uint32 param0, uint32 param1)
{
    _field_entry_policer_t *f_ent_pl; /* Field entry policer structure.*/
    _field_policer_t       *f_pl;     /* Policer descriptor.           */

    /* Input parameter check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    f_ent_pl = f_ent->policer;
    if (0 == (f_ent_pl->flags & _FP_POLICER_VALID)) {
        return (BCM_E_PARAM);
    }

    /* Get policer config. */
    BCM_IF_ERROR_RETURN(_bcm_field_policer_get(unit, f_ent_pl->pid, &f_pl));

    /* mode = 4 & 5 are undefined */
    if (param0 == 4 || param0 == 5 || param0 > 7) {
        FP_ERR(("FP(unit %d) Error: invalid meter mode=%d\n", unit, param0));
        return (BCM_E_PARAM);
    }

    /* Set meter mode. */
    switch (param0) {
      case BCM_FIELD_METER_MODE_DEFAULT:
      case BCM_FIELD_METER_MODE_FLOW:
          if ((0 == param1) || (BCM_FIELD_METER_PEAK == param1)) {
              f_pl->cfg.mode = bcmPolicerModePeak;
              f_pl->hw_flags |= _FP_POLICER_PEAK_DIRTY;
          } else {
              f_pl->cfg.mode = bcmPolicerModeCommitted;
              f_pl->hw_flags |= _FP_POLICER_COMMITTED_DIRTY;
          }
          break;
      case BCM_FIELD_METER_MODE_trTCM_COLOR_BLIND:
          f_pl->cfg.mode = bcmPolicerModeTrTcm; 
          f_pl->cfg.flags |= BCM_POLICER_COLOR_BLIND; 
          f_pl->hw_flags |= _FP_POLICER_DIRTY;
          break;
      case BCM_FIELD_METER_MODE_trTCM_COLOR_AWARE:
          f_pl->cfg.mode = bcmPolicerModeTrTcm; 
          f_pl->hw_flags |= _FP_POLICER_DIRTY;
          break;
      case BCM_FIELD_METER_MODE_srTCM_COLOR_BLIND:
          f_pl->cfg.mode = bcmPolicerModeSrTcm; 
          f_pl->cfg.flags |= BCM_POLICER_COLOR_BLIND; 
          f_pl->hw_flags |= _FP_POLICER_DIRTY;
          break;
      case BCM_FIELD_METER_MODE_srTCM_COLOR_AWARE:
          f_pl->cfg.mode = bcmPolicerModeSrTcm; 
          f_pl->hw_flags |= _FP_POLICER_DIRTY;
          break;
      default:
          return (BCM_E_PARAM);
    }

        f_ent->flags          |= _FP_ENTRY_DIRTY;

    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_action_update_counter
 * Purpose:
 *     Set counter config. 
 * Parameters:
 *     unit     - (IN) BCM device number. 
 *     f_ent    - (IN) Entry meter belongs to.
 *     param0   - (IN) Counter mode.
 *     param1   - (IN) Unused.
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_action_update_counter(int unit, _field_entry_t *f_ent,
                             uint32 param0, uint32 param1)
{
    _field_entry_stat_t    *f_ent_st;  /* Field entry stat structure.  */
    _field_stat_t          *f_st;      /* Field statistics descriptor. */
    bcm_field_stat_t       stat_arr[2];/* Requested statistic array.   */
    uint8                  nstat;      /* Statistics array size.       */
    int                    rv;         /* Operation return status.     */

    /* Input parameters check. */
    if (NULL == f_ent) {
        return (BCM_E_PARAM);
    }

    f_ent_st = &f_ent->statistic;

    /* Reject unused counters. */
    if (0 == (f_ent_st->flags & _FP_ENTRY_STAT_VALID)) {
        return (BCM_E_PARAM);
    }

    /* Free counters if entry was previously installed. */
    if (f_ent_st->flags & _FP_ENTRY_STAT_INSTALLED) {
        rv = _field_stat_hw_free (unit, f_ent);
        BCM_IF_ERROR_RETURN(rv);
    }

    /* Read policer configuration. */
    BCM_IF_ERROR_RETURN(_bcm_field_stat_get(unit, f_ent_st->sid, &f_st));

    /* Remove flags from previous installations. */ 
    f_ent_st->flags &= ~(_FP_ENTRY_STAT_USE_EVEN | _FP_ENTRY_STAT_USE_ODD);
    f_st->hw_flags &= ~(_FP_STAT_COUNTER_PAIR);

    switch (param0 & ~BCM_FIELD_COUNTER_MODE_BYTES) {
      case BCM_FIELD_COUNTER_MODE_NO_NO:
          f_ent_st->flags |= _FP_ENTRY_STAT_EMPTY; 
          return (BCM_E_NONE);
      case BCM_FIELD_COUNTER_MODE_DEFAULT: 
#if defined(BCM_TRIUMPH2_SUPPORT)
          if ((soc_feature(unit, soc_feature_field_vfp_flex_counter)) &&  
              (_BCM_FIELD_STAGE_LOOKUP == f_ent->group->stage_id)) {
              nstat = 2;
              stat_arr[0] = bcmFieldStatPackets;
              stat_arr[1] = bcmFieldStatBytes;
              f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          } else 
#endif /* BCM_TRIUMPH2_SUPPORT */
#if defined(BCM_FIREBOLT2_SUPPORT)
          if (SOC_IS_FIREBOLT2(unit) &&
              (_BCM_FIELD_STAGE_EGRESS == f_ent->group->stage_id)) {
              nstat = 1;
              stat_arr[0] = bcmFieldStatPackets;
              f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          } else 
#endif /* BCM_FIREBOLT2_SUPPORT */
          {
              f_ent_st->flags |= _FP_ENTRY_STAT_USE_EVEN;
              f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
              f_st->hw_flags |= _FP_STAT_COUNTER_PAIR;
              if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
                  nstat = 2;
                  stat_arr[0] = _bcmFieldStatBytesEven;
                  stat_arr[1] = _bcmFieldStatBytesOdd;
              } else {
                  nstat = 2;
                  stat_arr[0] = _bcmFieldStatPacketsEven; 
                  stat_arr[1] = _bcmFieldStatPacketsOdd; 
              }
          }
          break;
      case BCM_FIELD_COUNTER_MODE_YES_NO:
          f_ent_st->flags |= _FP_ENTRY_STAT_USE_ODD;
          f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          f_st->hw_flags |= _FP_STAT_COUNTER_PAIR;
          if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
              nstat = 2;
              stat_arr[0] = _bcmFieldStatBytesEven;
              stat_arr[1] = _bcmFieldStatBytesOdd;
          } else {
              nstat = 2;
              stat_arr[0] = _bcmFieldStatPacketsEven; 
              stat_arr[1] = _bcmFieldStatPacketsOdd; 
          }
          break;
      case BCM_FIELD_COUNTER_MODE_RED_NOTRED:
          nstat = 2;
          f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
              stat_arr[1] = bcmFieldStatRedBytes; 
              stat_arr[0] = bcmFieldStatNotRedBytes; 
          } else {
              stat_arr[1] = bcmFieldStatRedPackets; 
              stat_arr[0] = bcmFieldStatNotRedPackets; 
          }
          break;
      case BCM_FIELD_COUNTER_MODE_GREEN_NOTGREEN:
          nstat = 2;
          f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
              stat_arr[1] = bcmFieldStatGreenBytes;
              stat_arr[0] = bcmFieldStatNotGreenBytes;
          } else {
              stat_arr[1] = bcmFieldStatGreenPackets;
              stat_arr[0] = bcmFieldStatNotGreenPackets;
          }
          break;
      case BCM_FIELD_COUNTER_MODE_GREEN_RED:
          nstat = 2;
          f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
              stat_arr[1] = bcmFieldStatGreenBytes;
              stat_arr[0] = bcmFieldStatRedBytes;
          } else {
              stat_arr[1] = bcmFieldStatGreenPackets;
              stat_arr[0] = bcmFieldStatRedPackets;
          }
          break;
      case BCM_FIELD_COUNTER_MODE_GREEN_YELLOW:
          nstat = 2;
          f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
              stat_arr[1] = bcmFieldStatGreenBytes;
              stat_arr[0] = bcmFieldStatYellowBytes;
          } else {
              stat_arr[1] = bcmFieldStatGreenPackets;
              stat_arr[0] = bcmFieldStatYellowPackets;
          }
          break;
      case BCM_FIELD_COUNTER_MODE_RED_YELLOW:
          nstat = 2;
          f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
              stat_arr[1] = bcmFieldStatRedBytes;
              stat_arr[0] = bcmFieldStatYellowBytes;
          } else {
              stat_arr[1] = bcmFieldStatRedPackets;
              stat_arr[0] = bcmFieldStatYellowPackets;
          }
          break;
      case BCM_FIELD_COUNTER_MODE_GREEN:
          nstat = 1;
          f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
              stat_arr[0] = bcmFieldStatGreenBytes;
          } else {
              stat_arr[0] = bcmFieldStatGreenPackets;
          }
          break;
      case BCM_FIELD_COUNTER_MODE_YELLOW:
          nstat = 1;
          f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
              stat_arr[0] = bcmFieldStatYellowBytes; 
          } else {
              stat_arr[0] = bcmFieldStatYellowPackets; 
          }
          break;
      case BCM_FIELD_COUNTER_MODE_RED:
          nstat = 1;
          f_ent_st->flags &= ~_FP_ENTRY_STAT_EMPTY;
          if (param0 & BCM_FIELD_COUNTER_MODE_BYTES) {
              stat_arr[0] = bcmFieldStatRedBytes; 
          } else {
              stat_arr[0] = bcmFieldStatRedPackets; 
          }
          break;
      default:
          return (BCM_E_PARAM);
    }
    rv = _field_stat_array_init(unit, f_st, nstat, stat_arr);
    return (rv);
}

/*
 * Function: _field_action_add
 *
 * Purpose:
 *     Add action performed when entry rule is matched for a packet
 *
 * Parameters:
 *     unit  - (IN) BCM device number.
 *     fc    - (IN) Field control structure.
 *     f_ent - (IN) Field entry id.
 *     fa    - (IN) Field action structure. 
 * Returns:
 *     BCM_E_XXX
 */
int
_field_action_add(int unit, _field_control_t *fc, 
                  bcm_field_entry_t entry, _field_action_t *fa)
{
    int              action_support;  /* Action supported flag.       */
    _field_entry_t   *f_ent;          /* Field entry structure.       */
    _field_action_t  *fa_iter;        /* Field entry actions iterator.*/
    int               rv;             /* Operation return status.     */

    /* Get field entry structure pointer. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    BCM_IF_ERROR_RETURN(rv);


    /* Confirm that action is supported by device. */
    rv = fc->functions.fp_action_support_check(unit, f_ent, fa->action, 
                                               &action_support);
    BCM_IF_ERROR_RETURN(rv);
    if(FALSE == action_support) {
        FP_ERR(("FP(unit %d) Error: action=%s not supported\n", unit, 
                _field_action_name(fa->action)));
        return (BCM_E_UNAVAIL);
    }

    /* Check for existing actions that conflict with the new action. */ 
    fa_iter = f_ent->actions;
    while (fa_iter != NULL) {
        if (0 == (fa_iter->flags & _FP_ACTION_VALID)) {
            fa_iter = fa_iter->next;
            continue;
        } 
        rv = fc->functions.fp_action_conflict_check(unit, f_ent, 
                                                    fa_iter->action,
                                                    fa->action);
        if (BCM_FAILURE(rv)) {
            FP_ERR(("FP(unit %d) Error: action=%s conflicts with  \
                    existing action in entry=%d\n", unit,     \
                    _field_action_name(fa->action), entry ));
            return (rv);
        }
        fa_iter = fa_iter->next;
    }

    /* Check action parameters. */
    rv = fc->functions.fp_action_params_check(unit, f_ent, fa);
    if (BCM_FAILURE(rv)) {
        FP_ERR(("FP(unit %d) Error: action=%s parameters check failed (%d)\n", 
                unit, _field_action_name(fa->action), rv));
        return (rv);
    }

    /* Check dependency(s) of action */
    if (fc->functions.fp_action_depends_check) {
        rv = (*fc->functions.fp_action_depends_check)(unit, f_ent, fa);
        if (BCM_FAILURE(rv)) {
            FP_ERR(("FP(unit %d) Error: action=%s dependency check failed (%d)\n", 
                    unit, _field_action_name(fa->action), rv));
            return (rv);
        }
    }

    /* 
     * For counter actions, confirm a counter exists for the entry,
     * and record param0 as the counter mode. Param1 is not used.
     */
    if (fa->action == bcmFieldActionUpdateCounter) {
        rv = _field_action_update_counter (unit, f_ent, fa->param[0], fa->param[1]);
        BCM_IF_ERROR_RETURN(rv);
        sal_free(fa);
        if (0 == (f_ent->flags & _FP_ENTRY_DIRTY)) {
            f_ent->flags |= _FP_ENTRY_ACTION_ONLY_DIRTY;
        }
        f_ent->flags  |= _FP_ENTRY_DIRTY;
        return (BCM_E_NONE);
    }

    /* 
     * For meter configuration actions, confirm meter exists and set
     * its mode value to param0. Param1 is not used. Don't create an action
     * struct.
     */
    if (fa->action == bcmFieldActionMeterConfig) {
        rv = _field_action_meter_config (unit, f_ent, fa->param[0], fa->param[1]);
        BCM_IF_ERROR_RETURN(rv);
        sal_free(fa);
        if (0 == (f_ent->flags & _FP_ENTRY_DIRTY)) {
            f_ent->flags |= _FP_ENTRY_ACTION_ONLY_DIRTY;
        }
        f_ent->flags  |= _FP_ENTRY_DIRTY;
        return (BCM_E_NONE);
    }

    if (fa->action == bcmFieldActionColorIndependent) {
        if (fa->param[0])  {
            f_ent->flags |= _FP_ENTRY_COLOR_INDEPENDENT;
        } else {
            f_ent->flags &= ~_FP_ENTRY_COLOR_INDEPENDENT;
        }
        if (0 == (f_ent->flags & _FP_ENTRY_DIRTY)) {
            f_ent->flags |= _FP_ENTRY_ACTION_ONLY_DIRTY;
        }
        f_ent->flags  |= _FP_ENTRY_DIRTY;
        sal_free(fa);
        return (BCM_E_NONE);
    }

    /* Add action to front of entry's linked-list. */
    fa->next = f_ent->actions;
    f_ent->actions  = fa;
    /* 
     * Do not set action only dirty flag if qualifier parameter has 
     * been modified for this entry.
     */ 
    if (0 == (f_ent->flags & _FP_ENTRY_DIRTY)) {
        f_ent->flags |= _FP_ENTRY_ACTION_ONLY_DIRTY;
    }
    f_ent->flags    |= _FP_ENTRY_DIRTY;
    return (BCM_E_NONE);
}

/*
 * Function: _bcm_field_action_ports_add
 *
 * Purpose:
 *     Add action performed when entry rule is matched for a packet
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - entry ID
 *     action - Action to perform (bcmFieldActionXXX)
 *     param0 - Action parameter (use 0 if not required)
 *     param1 - Action parameter (use 0 if not required)
 *     param2 - Action parameter (use 0 if not required)
 *     param3 - Action parameter (use 0 if not required)
 *
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_bcm_field_action_ports_add(int unit,
                         bcm_field_entry_t entry,
                         bcm_field_action_t action,
                         uint32 param0,
                         uint32 param1,
                         uint32 param2, 
                         uint32 param3)
{
    _field_control_t    *fc;           /* Field control structure. */
    _field_action_t     *fa = NULL;    /* Field action descriptor. */
    int                 rv;            /* Operation return status. */

    FP_VVERB(("FP(unit %d) vverb: bcm_field_action_add(entry=%d, action=%s, \
        p0=%d, p1=%d, p2=%d)\n", unit, entry, \
        _field_action_name(action), param0, param1, param2));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* 
     * Allocate the action  descriptor.
     */
    rv = _field_action_alloc(unit, action, param0, param1, param2, param3, &fa);
    if (BCM_FAILURE(rv)) {
        FP_ERR(("FP(unit %d) Error: failure in _field_action_alloc()\n", unit));
        FP_UNLOCK(fc);
        return rv;
    }

    /*
     * Add action to entry actions list.
     */
    rv = _field_action_add(unit, fc, entry, fa);
    FP_UNLOCK(fc);
    if (BCM_FAILURE(rv)) {
        sal_free(fa);
        return rv;
    }
    return (BCM_E_NONE);
}

/*
 * Function: _bcm_field_action_ports_get
 *
 * Purpose:
 *     Get parameters associated with an entry action
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Entry ID
 *     action - Action to perform (bcmFieldActionXXX)
 *     param0 - (OUT) Action parameter
 *     param1 - (OUT) Action parameter
 *     param2 - (OUT) Action parameter
 *     param3 - (OUT) Action parameter
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found
 *     BCM_E_NOT_FOUND - No matching Action for entry
 *     BCM_E_PARAM     - paramX is NULL
 *     BCM_E_NONE      - Success
 */

STATIC int
_bcm_field_action_ports_get(int unit,
                         bcm_field_entry_t entry,
                         bcm_field_action_t action,
                         uint32 *param0,
                         uint32 *param1,
                         uint32 *param2, 
                         uint32 *param3)
{
    _field_entry_t      *f_ent;
    _field_action_t     *fa;
    _field_control_t    *fc;
    int                 rv;

    /* Input parameters check. */
    if ((NULL == param0) || (NULL == param1) || (NULL == param2)) {
            return (BCM_E_PARAM);
    }

    /* Lock the module. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Find matching action in the entry */
    for (fa = f_ent->actions; fa != NULL; fa = fa->next) {
        if (fa->action == action) {
            break;
        }
    }

    if (fa == NULL) {
        FP_UNLOCK(fc);
        FP_ERR(("FP(unit %d) Error: action not in entry=%d\n", unit, entry));
        return (BCM_E_NOT_FOUND);
    }

    *param0 = fa->param[0];
    *param1 = fa->param[1];
    *param2 = fa->param[2];
    *param3 = fa->param[3];
    
    /* Unlock the module. */
    FP_UNLOCK(fc);
    
    return (rv);
}

/*
 * Function:
 *     _bcm_field_slice_offset_to_tcam_idx
 *
 * Purpose:
 *     Given stage and tcam_index, 
 *     calculate slice and entry offset in the
 *
 * Parameters:
 *     unit     - (IN) BCM device number. 
 *     stage_fc - (IN) Pointer to field entry structure.
 *     slice    - (IN) Entry slice number.
 *     slice_idx -(IN) Entry offset in the slice.
 *     tcam_idx - (OUT) Entry tcam index. 
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_slice_offset_to_tcam_idx(int unit, _field_stage_t *stage_fc,
                                    int slice, int slice_idx, int *tcam_idx)
{
    _field_slice_t  *fs;          /* Field slice number.            */

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == tcam_idx))  {
        return (BCM_E_PARAM);
    }

    /* Given stage flags slice number and slice index,  calculate tcam index. */  
    fs = stage_fc->slices + slice;

    if ((stage_fc->flags & _FP_STAGE_HALF_SLICE) &&
        (slice_idx >= (fs->entry_count >> 1)) &&
        ((_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) ||
         (_BCM_FIELD_STAGE_LOOKUP == stage_fc->stage_id))) {
        /*
         * Entry in the second quater of the sw slice 
         * maps to the hw entry in the first quater 
         * of the secondary tcam.
         */
        *tcam_idx = fs->start_tcam_idx + slice_idx + (fs->entry_count / 2);
    } else {
        *tcam_idx = fs->start_tcam_idx + slice_idx;
    }
    return (BCM_E_NONE); 
}

/*
 * Function:
 *     _bcm_field_tcam_idx_to_slice_offset
 *
 * Purpose:
 *     Given stage and tcam_index, 
 *     calculate slice and entry offset in the
 *
 * Parameters:
 *     unit     - (IN) BCM device number. 
 *     stage_fc - (IN) Pointer to field entry structure.
 *     tcam_idx - (IN) Entry tcam index. 
 *     slice    - (OUT) Entry slice number.
 *     slice_idx -(OUT) Entry offset in the slice.
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_tcam_idx_to_slice_offset(int unit, _field_stage_t *stage_fc,
                                  int tcam_idx, int *slice, int *slice_idx)
{
    _field_slice_t  *fs;          /* Field slice number.         */
    int idx;                      /* Slices iteration index.     */

    /* Input parameters check. */
    if ((NULL == stage_fc) || (NULL == slice) || 
        (NULL == slice_idx) || (tcam_idx < 0))  {
        return (BCM_E_PARAM);
    }

    for (idx = 0; idx < stage_fc->tcam_slices; idx++) {
        fs = stage_fc->slices + idx;
        if (tcam_idx < (fs->start_tcam_idx + fs->entry_count)) {
            *slice = idx;
            *slice_idx = tcam_idx - fs->start_tcam_idx;
            break;
        }

        if (stage_fc->flags & _FP_STAGE_HALF_SLICE) {
            if (tcam_idx < (fs->start_tcam_idx + (fs->entry_count << 1))) {
                *slice = idx;
                *slice_idx = tcam_idx - fs->start_tcam_idx -  \
                          (fs->entry_count >> 1);
                break;
            }
        }
    }

    /* Tcam idx sanity check. */
    if (idx == stage_fc->tcam_slices) {
        return (BCM_E_PARAM);
    }
    return (BCM_E_NONE); 
}

/*
 * Function:
 *     _bcm_field_entry_tcam_idx_get
 *
 * Purpose:
 *     Get the TCAM index of an entry ID.
 *
 * Parameters:
 *     unit     - (IN) BCM device number. 
 *     f_ent    - (IN) Pointer to field entry structure.
 *     tcam_idx - (OUT) Entry tcam index. 
 *
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_entry_tcam_idx_get(int unit,_field_entry_t *f_ent, int *tcam_idx)
{
    _field_stage_t  *stage_fc;    /* Stage field control structure. */
    _field_slice_t  *fs;          /* Field slice number.            */
    int rv;                       /* Operation return status.       */

    /* Input parameters check. */
    if ((NULL == f_ent) || (NULL == tcam_idx))  {
        return (BCM_E_PARAM);
    }

    /* Requested entry structure sanity check. */
    if ((NULL == f_ent->group) || (NULL == f_ent->fs)) {
        return (BCM_E_PARAM);
    }

    /* Get stage control structure. */
    rv = _field_stage_control_get(unit, f_ent->group->stage_id, &stage_fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Given entry and stage flags calculate tcam index. */  
    fs = f_ent->fs;
    if ((stage_fc->flags & _FP_STAGE_HALF_SLICE) &&
        ((f_ent->flags & _FP_ENTRY_SECOND_HALF) || 
         (f_ent->slice_idx >= (fs->entry_count >> 1))) &&
        ((_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) ||
         (_BCM_FIELD_STAGE_LOOKUP == stage_fc->stage_id))) {
        /*
         * Entry in the second quater of the sw slice 
         * maps to the hw entry in the first quater 
         * of the secondary tcam.
         */
        *tcam_idx = fs->start_tcam_idx + f_ent->slice_idx +
            (fs->entry_count / 2);
    } else {
        *tcam_idx = fs->start_tcam_idx + f_ent->slice_idx;
    }
    return (BCM_E_NONE); 
}


/*
 * Function:
 *      _field_action_delete
 * Purpose:
 *      Delete field action from a field entry.
 * Parameters:
 *      unit   - (IN) BCM device number
 *      entry  - (IN) Entry ID
 *      action - (IN) Action to remove (bcmFieldActionXXX)
 *      param0 - (IN) Action parameter (use 0 if not required)
 *      param1 - (IN) Action parameter (use 0 if not required)
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_field_action_delete(int unit, bcm_field_entry_t entry, 
                        bcm_field_action_t action, 
                        uint32 param0, uint32 param1)
{
    _field_entry_t      *f_ent;
    _field_action_t     *fa;
    _field_action_t     *fa_prev = NULL;
    int                 rv;                /* Operation return status. */

    /* Get field entry descriptor. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        return (rv);
    }

    /* Special treatment for pre-historic actions. */
    switch (action) {
      case bcmFieldActionMeterConfig:
          /* Detach level 0 policer from the entry. */ 
          return  bcm_esw_field_entry_policer_detach(unit, entry, 0);
      case bcmFieldActionUpdateCounter:
          /* Free hw resources allocated for the statistics entity. */
          rv =  _field_stat_hw_free (unit, f_ent);
          BCM_IF_ERROR_RETURN(rv);
          f_ent->statistic.flags |= _FP_ENTRY_STAT_EMPTY;
          return (BCM_E_NONE);
      case  bcmFieldActionColorIndependent:
          f_ent->flags |= _FP_ENTRY_DIRTY;
          return (BCM_E_NONE);
      default:
          break;
    }


    /* Find the action in the entry */
    fa = f_ent->actions; /* start at head */

    while (fa != NULL) {
        if (fa->action != action) {
            fa_prev = fa;
            fa      = fa->next;
            continue;
        }

        /* Some actions might be applied multiple times.*/
        if (((action == bcmFieldActionMirrorIngress) ||
             (action == bcmFieldActionMirrorEgress)) && 
            (((uint32)_FP_INVALID_INDEX != param0) && 
             ((uint32)_FP_INVALID_INDEX != param1)))  {
            if ((fa->param[0] != param0)  || (fa->param[1] != param1)) { 
                fa_prev = fa;
                fa      = fa->next;
                continue;
            }
        }
        break; 
    }

    if (NULL == fa) {
        return (BCM_E_NOT_FOUND);
    }

    /* If entry is installed mark action as invalid. 
     * Invalid actions will be removed during entry remove/reinstall.
     */
    if (f_ent->flags & _FP_ENTRY_INSTALLED) {
        fa->flags  &= ~_FP_ACTION_VALID;
        /* 
         * Do not set action only dirty flag if qualifier parameter has 
         * been modified for this entry.
         */ 
        if (0 == (f_ent->flags & _FP_ENTRY_DIRTY)) {
            f_ent->flags |= _FP_ENTRY_ACTION_ONLY_DIRTY;
        }
        f_ent->flags |= _FP_ENTRY_DIRTY;
        return (BCM_E_NONE);
    }

    if (fa_prev != NULL) {
        fa_prev->next = fa->next;
    } else { /* matched head of list */
        f_ent->actions = fa->next;
    }

    /* okay to free action */
    sal_free(fa);
    fa = NULL;

   /* 
    * Do not set action only dirty flag if qualifier parameter has 
    * been modified for this entry.
    */ 
    if (0 == (f_ent->flags & _FP_ENTRY_DIRTY)) {
        f_ent->flags |= _FP_ENTRY_ACTION_ONLY_DIRTY;
    }
    f_ent->flags |= _FP_ENTRY_DIRTY;
    return (BCM_E_NONE);
}

#ifdef BCM_BRADLEY_SUPPORT
/*
 * Function:
 *     _bcm_field_36bit_counter_update
 * Description:
 *     Service routine used to update 64-bit software accumulated 36 bit counters.
 * Parameters:
 *     unit     - (IN) BCM device number. 
 *     new_val  - (IN) New hw counter value from. 
 *     result   - (IN/OUT) Operation result. 
 * Returns:
 *     BCM_E_XXX
 * Notes:
 *     This is for Bradley
 */
int
_bcm_field_36bit_counter_update(int unit, uint32 *new_val, 
                        _field_counter64_collect_t *result)
{
    uint64 hw_val;
    uint64 diff64;

    /* Input parameters check. */
    if ((NULL == new_val) || (NULL == result)) {
        return (BCM_E_PARAM);
    }

    /* Compose H/W counter value. */
    COMPILER_64_SET(hw_val, new_val[1], new_val[0]);

    if (COMPILER_64_LE(result->last_hw_value, hw_val)) {
        /* diff = hw_val - result->last_hw_value */
        COMPILER_64_ZERO(diff64);
        COMPILER_64_OR(diff64, hw_val);
        COMPILER_64_SUB_64(diff64, result->last_hw_value);
    } else {
        /* 
         * diff = 0xfffffffff - (result->last_hw_value - hw_val) + 1
         *      = 0x1000000000 - result->last_hw_value + hw_val
         */
        COMPILER_64_SET(diff64, 0x10, 0);
        COMPILER_64_SUB_64(diff64, result->last_hw_value);
        COMPILER_64_ADD_64(diff64, hw_val);
    }

    COMPILER_64_ADD_64(result->accumulated_counter, diff64);

    COMPILER_64_ZERO(result->last_hw_value);
    COMPILER_64_OR(result->last_hw_value, hw_val);

    return (BCM_E_NONE);
}
#endif /* BCM_BRADLEY_SUPPORT */
/*
 * Function:
 *  _bcm_field_32bit_counter_update
 * Description:
 *  Service routine used to update 64-bit software accumulated 32 bit counter.
 * Parameters:
 *   unit     - (IN) BCM device number. 
 *   new_val  - (IN) New hw counter value from. 
 *   result   - (IN/OUT) Operation result. 
 * Returns:
 *   BCM_E_XXX
 */
int
_bcm_field_32bit_counter_update(int unit, uint32 *new_val, 
                        _field_counter32_collect_t *result)
{
    uint32 diff;
    uint64 diff64;

    /* Input parameters check. */
    if ((NULL == new_val) || (NULL == result)) {
        return (BCM_E_PARAM);
    }

    if (result->last_hw_value <= new_val[0]) {
        diff = new_val[0] - result->last_hw_value;
    } else {
        diff = ((0xFFFFFFFFL) - result->last_hw_value) + new_val[0] + 1;
    }

    COMPILER_64_SET(diff64, 0, diff);
    COMPILER_64_ADD_64(result->accumulated_counter, diff64);

    result->last_hw_value = new_val[0];

    return (BCM_E_NONE);
}

/*
 * Function:
 *  _bcm_field_29bit_counter_update
 * Description:
 *  Service routine used to update 64-bit software accumulated 29 bit counter.
 * Parameters:
 *   unit     - (IN) BCM device number. 
 *   new_val  - (IN) New hw counter value from. 
 *   result   - (IN/OUT) Operation result. 
 * Returns:
 *   BCM_E_XXX
 */
int
_bcm_field_29bit_counter_update(int unit, uint32 *new_val, 
                        _field_counter32_collect_t *result)
{
    uint32 diff;
    uint64 diff64;

    /* Input parameters check. */
    if ((NULL == new_val) || (NULL == result)) {
        return (BCM_E_PARAM);
    }

    if (result->last_hw_value <= new_val[0]) {
        diff = new_val[0] - result->last_hw_value;
    } else {
        diff = ((1 << 29) - 1) - (result->last_hw_value - new_val[0]) + 1;
    }

    COMPILER_64_SET(diff64, 0, diff);
    COMPILER_64_ADD_64(result->accumulated_counter, diff64);

    result->last_hw_value = new_val[0];

    return (BCM_E_NONE);
}
#if defined(BCM_TRX_SUPPORT)
/*
 * Function:
 *     _bcm_field_35bit_counter_update
 * Description:
 *     Service routine used to update 64-bit software accumulated 35 bit counters.
 * Parameters:
 *     unit     - (IN) BCM device number. 
 *     new_val  - (IN) New hw counter value from. 
 *     result   - (IN/OUT) Operation result. 
 * Returns:
 *     BCM_E_XXX
 * Notes:
 *     This is for BYTE_COUNTER field
 */
int
_bcm_field_35bit_counter_update(int unit, uint32 *new_val, 
                        _field_counter64_collect_t *result)
{
    uint64 hw_val;
    uint64 diff64;

    /* Input parameters check. */
    if ((NULL == new_val) || (NULL == result)) {
        return (BCM_E_PARAM);
    }

    /* Compose H/W counter value. */
    COMPILER_64_SET(hw_val, new_val[1], new_val[0]);

    if (COMPILER_64_LE(result->last_hw_value, hw_val)) {
        /* diff = hw_val - result->last_hw_value */
        COMPILER_64_ZERO(diff64);
        COMPILER_64_OR(diff64, hw_val);
        COMPILER_64_SUB_64(diff64, result->last_hw_value);
    } else {
        /* 
         * diff = 0x7ffffffff - (result->last_hw_value - hw_val) + 1
         *      = 0x800000000 - result->last_hw_value + hw_val
         */
        COMPILER_64_SET(diff64, 0x8, 0);
        COMPILER_64_SUB_64(diff64, result->last_hw_value);
        COMPILER_64_ADD_64(diff64, hw_val);
    }

    COMPILER_64_ADD_64(result->accumulated_counter, diff64);

    COMPILER_64_ZERO(result->last_hw_value);
    COMPILER_64_OR(result->last_hw_value, hw_val);

    return (BCM_E_NONE);
}
#endif /* BCM_TRX_SUPPORT */


/*
 * Function:
 *  _bcm_field_sw_counter_update
 * Description:
 *  Service routine used to update 64-bit software accumulated counters.
 *  based on hw memory block.
 * Parameters:
 *   unit     - (IN) BCM device number. 
 *   stage_fc - (IN/OUT) Stage field control structure.
 *   mem      - (IN) Counters memory.
 *   idx_min  - (IN) First counter index in the buffer.
 *   idx_max  - (IN) Last counter index in the buffer. 
 *   buf      - (IN) Counters buffer.
 *   flags    - (IN) Device counters flags.     
 * Returns:
 *  BCM_E_XXX
 */
int
_bcm_field_sw_counter_update(int unit, _field_stage_t *stage_fc, soc_mem_t mem,
                         int idx_min, int idx_max, char *buf, int flags)
{
    _field_control_t       *fc;        /* Field control structure.         */
    uint32                 *entry_p;   /* HW entry pointer.                */
    int                    buf_offset; /* Offset into counters buffer.     */
    int                    idx;        /* Iteration index.                 */ 
    int                    rv;         /* Operartion return status.        */


    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    for (idx = idx_min, buf_offset = 0; idx <= idx_max; idx++, buf_offset++) {
        /* Read counter value from the first memory. */
        entry_p = soc_mem_table_idx_to_pointer(unit, mem, uint32 *,
                                               buf, buf_offset);

        /* Process accumulated counter value. */
        if (flags & _FIELD_FIRST_MEMORY_COUNTERS) {
            rv = fc->functions.fp_counter_get(unit, stage_fc, mem,
                                              entry_p, INVALIDm,
                                              NULL, idx, NULL, NULL);
        } else {
            rv = fc->functions.fp_counter_get(unit, stage_fc, INVALIDm,
                                              NULL, mem, entry_p, idx,
                                              NULL, NULL);
        }
        if (BCM_FAILURE(rv)) {
            break;
        }
    }
    return (BCM_E_NONE);
}


/*
 * Function:
 *    _field_mem_counters_read
 * Description:
 *    Service routine used to collect 64-bit software accumulated counters.
 *    for a specific stage.
 * Parameters:
 *    unit     - (IN) BCM device number. 
 *    stage_fc - (IN/OUT) Stage field control structure.
 *    mem      - (IN) Counters memory. 
 * Returns:
 *  BCM_E_XXX
 */

STATIC int
_field_mem_counters_read(int unit, _field_stage_t *stage_fc,
                              soc_mem_t mem, int flags)
{
    int       buf_end_idx;           /* Buffer end index.         */ 
    int       alloc_size;            /* DMA buffer size.          */
    int       max_idx;               /* Counter memory index max. */   
    int       min_idx;               /* Counter memory index min. */   
    char      *buf;                  /* Buffer to read the table. */
    int       idx;                   /* Table iteration index.    */                
    int       rv = BCM_E_NONE;   /* Operation return value.   */


    /* Input parameters check. */ 
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    /* Make sure memory is valid */ 
    if (INVALIDm == mem) {
        return (BCM_E_NONE);
    }

    /* Get table boundaries. */
    min_idx = soc_mem_index_min(unit, mem);
    max_idx = soc_mem_index_max(unit, mem);

    /* Allocate memory buffer. */
    alloc_size = (_FP_64_COUNTER_BUCKET * sizeof(fp_counter_table_entry_t));
    buf = soc_cm_salloc(unit, alloc_size, "fp_64_bit_counter");
    if (buf == NULL) {
        return (BCM_E_MEMORY);
    }

    /* Dma part of the table & update software counters. */
    soc_mem_lock(unit, mem);
    for (idx = min_idx; idx <= max_idx; idx += _FP_64_COUNTER_BUCKET) {
        buf_end_idx = MIN(max_idx, (idx + _FP_64_COUNTER_BUCKET - 1));
        /* Dma range of entries in counter table. */
        rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, idx,
                                    buf_end_idx, buf);
        if (BCM_FAILURE(rv)) {
            break;
        }
         
        /* Update software counters. */
        rv = _bcm_field_sw_counter_update(unit, stage_fc, mem, idx, 
                                          buf_end_idx, buf, flags);
        if (BCM_FAILURE(rv)) {
            break;
        }
    }
    soc_mem_unlock(unit, mem);
    soc_cm_sfree(unit, buf);
    return (rv);
}


/*
 * Function:
 *     _field_stage_external_counters_collect
 * Description:
 *     Service routine used to coolect  64-bit software accumulated counters.
 *          For the External-FP (Triumph).
 * Parameters:
 *     unit     - (IN) BCM device number. 
 *     fc       - (IN) Field control structure. 
 *     stage_fc - (IN/OUT) Stage field control structure.
 * Returns:
 *     BCM_E_XXX
 */

STATIC int
_field_stage_external_counters_collect (int unit, _field_control_t *fc, 
                                        _field_stage_t *stage_fc)
{
    if ((stage_fc->_field_x32_counters == NULL) 
#if defined(BCM_BRADLEY_SUPPORT) || defined(BCM_TRX_SUPPORT)
        && (stage_fc->_field_x64_counters == NULL)
#endif /* BCM_BRADLEY_SUPPORT || BCM_TRX_SUPPORT */
        )
    {
        return (BCM_E_UNAVAIL);
    }

#ifdef BCM_TRIUMPH_SUPPORT
    BCM_IF_ERROR_RETURN
        (_bcm_field_tr_external_counters_collect(unit, stage_fc));
#endif /* BCM_TRIUMPH_SUPPORT */

    return (BCM_E_NONE);
}

/*
 * Function:
 *  _field_stage_counters_collect
 * Description:
 *  Service routine used to coolect  64-bit software accumulated counters.
 *  for a specific stage.
 * Parameters:
 *   unit     - (IN) BCM device number. 
 *   fc       - (IN) Field control structure. 
 *   stage_fc - (IN/OUT) Stage field control structure.
 * Returns:
 *  BCM_E_XXX
 * Notes:
 *  None.
 */

STATIC int
_field_stage_counters_collect (int unit, _field_control_t *fc, 
                               _field_stage_t *stage_fc)
{
    soc_mem_t  counter_x_mem;        /* First counters memory.    */
    soc_mem_t  counter_y_mem;        /* Second counters memory    */
                                     /* for dual pipeline devices.*/

    /* Input parameters check. */ 
    if (NULL == stage_fc) {
        return (BCM_E_PARAM);
    }

    /*  Check if counters are available at this stage. */ 
    if ((stage_fc->_field_x32_counters == NULL) 
#if defined(BCM_BRADLEY_SUPPORT) || defined(BCM_TRX_SUPPORT)
        && (stage_fc->_field_x64_counters == NULL)
#endif /* BCM_BRADLEY_SUPPORT || BCM_TRX_SUPPORT */
        )
    {
        return (BCM_E_UNAVAIL);
    }

    /* Get counters memory for the stage. */
    BCM_IF_ERROR_RETURN(_field_counter_mem_get(unit, stage_fc,
                                               &counter_x_mem, &counter_y_mem));

    /* If stage doesn't have counters - we are done. */
    if ((INVALIDm == counter_x_mem) && (INVALIDm == counter_y_mem)) {
        return (BCM_E_NONE);
    } 

    if (INVALIDm != counter_x_mem) {
        BCM_IF_ERROR_RETURN
            (_field_mem_counters_read(unit, stage_fc, counter_x_mem,
                                      _FIELD_FIRST_MEMORY_COUNTERS));
    }

#if defined(BCM_BRADLEY_SUPPORT) || defined(BCM_SCORPION_SUPPORT)
    if (INVALIDm != counter_y_mem) {
        BCM_IF_ERROR_RETURN
            (_field_mem_counters_read(unit, stage_fc, counter_y_mem,
                                      _FIELD_SECOND_MEMORY_COUNTERS));
    }
#endif /* BCM_BRADLEY_SUPPORT || BCM_SCORPION_SUPPORT */
    return (BCM_E_NONE);
}


/*
 * Function:
 *  _bcm_esw_fp_counters_collect
 * Description:
 *  Callback routine executed each counter cycle to add up the
 *  64-bit software accumulated counter values.
 * Parameters:
 *  unit -  (IN) BCM device number. 
 * Returns:
 *  BCM_E_XXX
 * Notes:
 *  None.
 */

STATIC void
_bcm_esw_fp_counters_collect(int unit)
{
   _field_control_t  *fc;           /* Field control structure.      */ 
   _field_stage_t    *stage_fc;     /* Stage field control iterator. */

   if (BCM_FAILURE(_field_control_get(unit, &fc))) {
       return;
   }

   FP_LOCK(fc);

   /* Collect  counters from each fp pipeline stage. */
   stage_fc = fc->stages;
   while (NULL != stage_fc) {
        if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
           _field_stage_external_counters_collect(unit, fc, stage_fc);
        } else {
           _field_stage_counters_collect(unit, fc, stage_fc);
        }
       stage_fc = stage_fc->next; 
   }

   FP_UNLOCK(fc);
   return;
}

/* Function    : 
 *           _field_qualify_IpProtocolCommon_get
 * Description : 
 *           Get qualifier common L3 protocol ID
 * Parameters  : 
 *   unit     (IN) BCM device number
 *   entry    (IN) Field entry to qualify
 *   qual_id  (IN) Field qualifier id. 
 *   protocol (OUT) Protocol name to qualify
 * Returns: 
 *   BCM_E_XXX
 */
STATIC int
_field_qualify_IpProtocolCommon_get(int unit, 
                                    bcm_field_entry_t entry, 
                                    bcm_field_qualify_t qual_id,
                                    bcm_field_IpProtocolCommon_t *protocol)
{
    uint8  data;              /* HW encoded data.         */
    uint8  mask;              /* HW encoded mask.         */
    int    rv;                /* Operation return status. */

    if (NULL == protocol) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */
    rv = _bcm_field_entry_qualifier_uint8_get(unit, entry,
                                       qual_id, &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    if ((0 == data)  && (0x7 == mask)) {
       *protocol = bcmFieldIpProtocolCommonTcp;
    } else  if ((1 == data)  && (0x7 == mask)) {
       *protocol = bcmFieldIpProtocolCommonUdp;
    } else  if ((2 == data)  && (0x7 == mask)) {
       *protocol = bcmFieldIpProtocolCommonIgmp;
    } else  if ((3 == data)  && (0x7 == mask)) {
       *protocol = bcmFieldIpProtocolCommonIcmp;
    } else  if ((4 == data)  && (0x7 == mask)) {
       *protocol = bcmFieldIpProtocolCommonIp6Icmp;
    } else  if ((5 == data)  && (0x7 == mask)) {
       *protocol = bcmFieldIpProtocolCommonIp6HopByHop;
    } else  if ((6 == data)  && (0x7 == mask)) {
       *protocol = bcmFieldIpProtocolCommonIpInIp;
    } else  if ((0 == data)  && (0x6 == mask)) {
       *protocol = bcmFieldIpProtocolCommonTcpUdp;
    } else {
        return (BCM_E_INTERNAL);
    }
    return (BCM_E_NONE);
}

/* Function    : 
 *           _field_qualify_IpProtocolCommon
 * Description : 
 *           Qualify common L3 protocol ID
 * Parameters  : 
 *   unit     (IN) BCM device number
 *   entry    (IN) Field entry to qualify
 *   qual_id  (IN) Field qualifier id. 
 *   protocol (IN) Protocol name to qualify
 * Returns: 
 *   BCM_E_XXX
 */
STATIC int
_field_qualify_IpProtocolCommon(int unit, bcm_field_entry_t entry, 
                                bcm_field_qualify_t qual_id,
                                bcm_field_IpProtocolCommon_t protocol)
{
    uint32   data;
    uint32   mask;

    if (protocol >= bcmFieldIpProtocolCommonCount) {
        return (BCM_E_PARAM);
    }

    switch (protocol) {
      case bcmFieldIpProtocolCommonTcp:
          data = 0x00;
          mask = 0x07;
          break;
      case bcmFieldIpProtocolCommonUdp:
          data = 0x01;
          mask = 0x07;
          break;
      case bcmFieldIpProtocolCommonIgmp:
          data = 0x02;
          mask = 0x07;
          break;
      case bcmFieldIpProtocolCommonIcmp:
          data = 0x03;
          mask = 0x07;
          break;
      case bcmFieldIpProtocolCommonIp6Icmp:
          data = 0x04;
          mask = 0x07;
          break;
      case bcmFieldIpProtocolCommonIp6HopByHop:
          /* TRX  devices do not use extension headers 
           * for packet ip protocol is determination. 
           * Please use  bcm_esw_field_qualify_ExtensionHeaderType */
          if (SOC_IS_TRX(unit)) {
              return (BCM_E_UNAVAIL);
          }
          data = 0x05;
          mask = 0x07;
          break;
      case bcmFieldIpProtocolCommonIpInIp:
          data = 0x06;
          mask = 0x07;
          break;
      case bcmFieldIpProtocolCommonTcpUdp:
          data = 0x00;
          mask = 0x06;
          break;
      default:
          return (BCM_E_UNAVAIL); 
    }
    return  _field_qualify32(unit, entry, qual_id, data, mask);
}
 
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) \
    || defined(BCM_RAPTOR_SUPPORT)

/* Function    : _field_qualify_IpFrag
 * Description : qualify on Ip Frag Info.
 * Parameters  : (IN) unit       BCM device number
 *               (IN) entry      Field entry to qualify
 *               (IN) qual_id    Field qualifier id. 
 *               (IN) frag_info  bcm_field_IpFrag_t to qualify
 * Returns     : BCM_E_XXX
 */
STATIC int 
_field_qualify_IpFrag(int unit, bcm_field_entry_t entry,
                      bcm_field_qualify_t qual_id,
                      bcm_field_IpFrag_t frag_info)
{
    int             rv;
    _field_entry_t *f_ent;
    uint32          data;
    uint32          mask;

    if (frag_info >= bcmFieldIpFragCount) {
        return (BCM_E_PARAM);
    }

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    if ((_BCM_FIELD_STAGE_INGRESS == f_ent->group->stage_id) || 
#if defined (BCM_TRX_SUPPORT)
        (SOC_IS_TRX(unit) &&
         (_BCM_FIELD_STAGE_LOOKUP == f_ent->group->stage_id)) ||
#endif /* BCM_TRX_SUPPORT */
        (_BCM_FIELD_STAGE_EXTERNAL == f_ent->group->stage_id)) {
        /*
         * IP_FRAG_INFO[1] = (IP_OFFSET == 0) & !MoreFragment
         * IP_FRAG_INFO[0] = (IP_OFFSET == 0)
         */
        switch(frag_info) {
          case bcmFieldIpFragAny:   
              /* Any fragment of fragmented packet */
              data = 0x00;
              mask = 0x02;
              break;
          case bcmFieldIpFragNon:   
              /* Non-fragmented packet */
              data = 0x02;
              mask = 0x02;
              break;
          case bcmFieldIpFragFirst: 
              /* First fragment of fragmented packet*/
              data = 0x01;
              mask = 0x03;
              break;
          case bcmFieldIpFragNonOrFirst: 
              /* Non-fragmented or first fragment */
              data = 0x01;
              mask = 0x01;
              break;
          case bcmFieldIpFragNotFirst:   
              /* Not the first fragment */
              data = 0x00;
              mask = 0x03;
              break;
          default:
              return (BCM_E_PARAM);
        }
    }
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    else if((_BCM_FIELD_STAGE_EGRESS == f_ent->group->stage_id) ||
            (_BCM_FIELD_STAGE_LOOKUP == f_ent->group->stage_id)) {
        /* 
         * 00 : Not a fragment
         * 10 : First fragment
         * 11 : Non-first fragment
         * 01 : Reserved
         */
        switch(frag_info) {
          case bcmFieldIpFragAny:
              /* Any fragment of fragmented packet */
              data = 0x02;
              mask = 0x02;
              break;
          case bcmFieldIpFragNon:
              /* Non-fragmented packet */
              data = 0x00;
              mask = 0x03;
              break;
          case bcmFieldIpFragFirst:
              /* First fragment of fragmented packet*/
              data = 0x02;
              mask = 0x03;
              break;
          case bcmFieldIpFragNonOrFirst:
              /* Non-fragmented or first fragment */
              data = 0x00;
              mask = 0x01;
              break;
          case bcmFieldIpFragNotFirst:
              /* Not the first fragment */
              data = 0x03;
              mask = 0x03;
              break;
          default:
              return (BCM_E_PARAM);
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */ 
    else {
        return (BCM_E_INTERNAL);
    }
    rv = _field_qualify32(unit, entry, qual_id, data, mask);
    return (rv);
}


/* Function    : _field_qualify_IpFrag_get
 * Description : qualify on Ip Frag Info.
 * Parameters  : (IN) unit       BCM device number
 *               (IN) entry      Field entry to qualify
 *               (IN) qual_id    Field qualifier id. 
 *               (OUT) frag_info  bcm_field_IpFrag_t to qualify
 * Returns     : BCM_E_XXX
 */
STATIC int 
_field_qualify_IpFrag_get(int unit, bcm_field_entry_t entry,
                          bcm_field_qualify_t qual_id,
                          bcm_field_IpFrag_t *frag_info)
{
    _field_entry_t *f_ent;       /* Field entry structure.      */
    uint32    hw_data = 0;       /* HW buffer data.             */
    uint32    hw_mask = 0;       /* HW buffer mask.             */
    int       rv;                /* Operation return stauts.    */

    /* Input parameters check. */
    if (NULL == frag_info) {
        return (BCM_E_PARAM);
    }

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                               bcmFieldQualifyIpFrag,
                                               &hw_data, &hw_mask);
    BCM_IF_ERROR_RETURN(rv);

    if ((_BCM_FIELD_STAGE_INGRESS == f_ent->group->stage_id) || 
#if defined (BCM_TRX_SUPPORT)
        (SOC_IS_TRX(unit) &&
         (_BCM_FIELD_STAGE_LOOKUP == f_ent->group->stage_id)) ||
#endif /* BCM_TRX_SUPPORT */
        (_BCM_FIELD_STAGE_EXTERNAL == f_ent->group->stage_id)) {
        /*
         * IP_FRAG_INFO[1] = (IP_OFFSET == 0) & !MoreFragment
         * IP_FRAG_INFO[0] = (IP_OFFSET == 0)
         */

        if ((hw_data == 0x2) && (hw_mask == 0x2)) {
            *frag_info = bcmFieldIpFragNon;
        } else  if ((hw_data == 0x1) && (hw_mask == 0x3)) {
            *frag_info = bcmFieldIpFragFirst; 
        } else  if ((hw_data == 0x1) && (hw_mask == 0x1)) {
            *frag_info = bcmFieldIpFragNonOrFirst; 
        } else  if ((hw_data == 0x0) && (hw_mask == 0x3)) {
            *frag_info = bcmFieldIpFragNotFirst;   
        } else  if ((hw_data == 0x0) && (hw_mask == 0x2)) {
            *frag_info = bcmFieldIpFragAny;   
        } else {
            return (BCM_E_INTERNAL);
        }
    }
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    else if((_BCM_FIELD_STAGE_EGRESS == f_ent->group->stage_id) ||
            (_BCM_FIELD_STAGE_LOOKUP == f_ent->group->stage_id)) {
        /* 
         * 00 : Not a fragment
         * 10 : First fragment
         * 11 : Non-first fragment
         * 01 : Reserved
         */
        if ((hw_data == 0x0) && (hw_mask == 0x3)) {
            *frag_info = bcmFieldIpFragNon;
        } else  if ((hw_data == 0x2) && (hw_mask == 0x3)) {
            *frag_info = bcmFieldIpFragFirst; 
        } else  if ((hw_data == 0x0) && (hw_mask == 0x1)) {
            *frag_info = bcmFieldIpFragNonOrFirst; 
        } else  if ((hw_data == 0x3) && (hw_mask == 0x3)) {
            *frag_info = bcmFieldIpFragNotFirst;   
        } else  if ((hw_data == 0x2) && (hw_mask == 0x2)) {
            *frag_info = bcmFieldIpFragAny;   
        } else {
            return (BCM_E_INTERNAL);
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */ 
    else {
        return (BCM_E_INTERNAL);
    }
    return (BCM_E_NONE);
}


#endif /* BCM_FIREBOLT_SUPPORT || BCM_TRX_SUPPORT || BCM_RAPTOR_SUPPORT */

/*
 * Function:
 *     _field_qual_selectors_insert
 * Purpose:
 *     Initialize field group select codes.
 * Parameters:
 *     unit        - (IN) BCM device number.
 *     candidate   - (IN) Inserted selector set.
 *     parts_count - (IN) Number of tcam parts. 
 *     selector    - (IN/OUT) Result selector set. 
 * 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_qual_selectors_insert (int unit, _field_sel_t *candidate, 
                              uint8 parts_count, 
                              _bcm_field_selector_t *selector)
{
    uint8 idx;                      /* Tcam parts iterator.            */
    uint8 selected_part;            /* Tcam part selected for 
                                       qualifier installation.         */
    uint8 update_count_min;         /* Minimum selectors update count. */
    uint8 update_count;             /* Number of updates required 
                                       to accommodate qualifier.       */ 
    int rv;                         /* Operation return status.        */

    /* Input parameters check. */
    if ((NULL == candidate) || (NULL == selector)) {
        return (BCM_E_PARAM);
    }

    update_count_min = _FP_INVALID_INDEX;
    selected_part = _FP_INVALID_INDEX;

    for (idx = 0; idx < parts_count; idx++) {
        update_count = 0;

        /* Test if selector can be inserted in a specific tcam part. */
        rv = _field_selector_diff(unit, candidate, idx, selector, &update_count);
        if (BCM_FAILURE(rv)) {
            continue;
        } 

        if (update_count < update_count_min) {
            update_count_min = update_count;
            selected_part = idx;
        }
    }

    /* Check if any tcam part can accommodate all the required selectors. */
    if ((uint8)_FP_INVALID_INDEX == selected_part) {
        return (BCM_E_RESOURCE);
    }

    /* Insert selector configuration. */
    rv = _field_selector_insert(candidate, selected_part, selector);
    return (rv);
}

/*
 * Function:
 *     _field_qual_selectors_sort
 * Purpose:
 *     Sorf field qualifiers select codes.
 * Parameters:
 *     unit        - (IN) BCM device number.
 *     candidate   - (IN) Inserted selector set.
 *     parts_count - (IN) Number of tcam parts. 
 *     f_qual_arr  - (IN/OUT) Result selector set. 
 * 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_qual_selectors_sort (int unit,  
                            _field_sel_t *candidate, 
                            uint8 parts_count, 
                            _bcm_field_qual_info_t *f_qual)
{
    uint8 idx;                      /* Tcam parts iterator.               */
    uint8 conf_idx;                 /* Configurations iterator.           */
    uint8 selected_part;            /* Tcam part selected for 
                                       qualifier installation.            */
    uint8 update_count_min;         /* Minimum selectors update count.    */
    uint8 update_count;             /* Number of updates required 
                                       to accommodate qualifier.          */ 
    int rv;                         /* Operation return status.           */
    _bcm_field_selector_t *selector;/* Qualifier select codes config.     */

    /* Input parameters check. */
    if ((NULL == candidate) || (NULL == f_qual)) {
        return (BCM_E_PARAM);
    }

    /* Don't sort if only one configuration is available. */
    if (f_qual->conf_sz <= 1) {
        return (BCM_E_NONE);
    }

    /* Get number of updates required for each qualifier configuration. */
    for (conf_idx = 0; conf_idx < f_qual->conf_sz; conf_idx++) {
        update_count_min = _FP_INVALID_INDEX;
        selected_part = _FP_INVALID_INDEX;
        selector = &((f_qual->conf_arr[conf_idx]).selector);

        for (idx = 0; idx < parts_count; idx++) {
            update_count = 0;

            /* Test if selector can be inserted in a specific tcam part. */
            rv = _field_selector_diff(unit, candidate, idx, 
                                      selector, &update_count);
            if (BCM_FAILURE(rv)) {
                continue;
            } 

            if (update_count < update_count_min) {
                update_count_min = update_count;
                selected_part = idx;
            }
        }
        /* Keep minimum number of required updates. */ 
        selector->update_count  =  update_count_min;
    }

    /* Qualifier configurations sort based on number of updates required.  */
    _shr_sort(f_qual->conf_arr, f_qual->conf_sz, 
               sizeof(_bcm_field_qual_conf_t), _field_selector_update_cmp);
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _field_group_selectors_init
 * Purpose:
 *     Initialize field group select codes.
 * Parameters:
 *     unit   - (IN) BCM device number.
 *     fg     - (IN/OUT) Field group structure.
 * 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_selectors_init(int unit, _field_group_t *fg)
{
    /* Input parameters check. */
    if (NULL == fg) {
        return (BCM_E_PARAM);
    }

    fg->sel_codes[0].intraslice = _FP_SELCODE_DONT_USE;
    if (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
        if (fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            fg->sel_codes[2].intraslice = _FP_SELCODE_DONT_USE;
        } else {
            fg->sel_codes[1].intraslice = _FP_SELCODE_DONT_USE;
        } 
    } else if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
        fg->sel_codes[1].intraslice = _FP_SELCODE_DONT_USE;
        fg->sel_codes[2].intraslice = _FP_SELCODE_DONT_USE;
    }

    fg->sel_codes[0].secondary = _FP_SELCODE_DONT_USE;
    if (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
        if (fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
            fg->sel_codes[1].secondary = _FP_SELCODE_DONT_USE;
            fg->sel_codes[2].secondary = _FP_SELCODE_DONT_USE;
        } 
    } else if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
        fg->sel_codes[1].secondary = _FP_SELCODE_DONT_USE;
        fg->sel_codes[2].secondary = _FP_SELCODE_DONT_USE;
    }

    return BCM_E_NONE;
}

/*
 * Function:
 *     _field_qualifiers_info_get
 * Purpose:
 *     Copy qualifiers configuration for a given qualifiers set.
 * Parameters:
 *     unit          - (IN) BCM device number.
 *     stage_fc      - (IN) Stage Field control structure.
 *     qset_req      - (IN) Client qualifier set.
 *     f_qual_arr    - (OUT)Qualifiers information array.
 *     qual_arr_size - (OUT)Qualifiers information array size.
 * 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_qualifiers_info_get (int unit, _field_stage_t *stage_fc, 
                            bcm_field_qset_t *qset_req,
                            _bcm_field_qual_info_t ***f_qual_arr,
                            uint16 *qual_arr_size)
{
    uint16 idx;              /* Qualifier set iterator.   */
    uint16 arr_idx;          /* Qualifiers array index.   */ 

    /* Input parameters check. */
    if ((NULL == f_qual_arr) || (NULL == qset_req) || 
        (NULL == qual_arr_size) || (NULL == stage_fc)) {
        return (BCM_E_PARAM);
    }

    /* Get number of qualifiers in requested qualifier set. */
    *qual_arr_size = 0;
    for(idx = 0; idx < _SHR_BITDCLSIZE(BCM_FIELD_QUALIFY_MAX); idx++) {
        *qual_arr_size += _shr_popcount(qset_req->w[idx]);
    }
    

    /* Allocate & initialize group select codes array. */
    _FP_XGS3_ALLOC((*f_qual_arr), 
                   (*qual_arr_size * sizeof(_bcm_field_qual_info_t *)),
                   "Field qualifiers");
    if (NULL == (*f_qual_arr)) {
        return (BCM_E_MEMORY);
    }


    /* Copy individual qualifiers information from the requested qset */
    arr_idx = 0;
    for (idx = 0; idx < _bcmFieldQualifyCount; idx++) {
        /* Skip unused qualifiers. */
        if (0 == BCM_FIELD_QSET_TEST((*qset_req), idx)) {
            continue;
        }

        /* Qualifiers support check. */
        if (NULL == stage_fc->f_qual_arr[idx]) { 
            sal_free (*f_qual_arr);
            return (BCM_E_RESOURCE);
        }

        (*f_qual_arr)[arr_idx] = stage_fc->f_qual_arr[idx];
        arr_idx++;
        if (arr_idx == (*qual_arr_size)) {
            break;
        }
    }

    /* Qualifier array elements are sorted so less frequently present 
       qualifiers appear first.  */
    _shr_sort((*f_qual_arr), *qual_arr_size, sizeof(_bcm_field_qual_info_t *), 
              _field_qual_info_cmp);

    return (BCM_E_NONE);
}
/*
 * Function:
 *     _field_qual_offsets_copy
 * Purpose:
 *     Copy group qualifiers offsets.    
 * Parameters:
 *     unit       - (IN) BCM unit number.
 *     fg         - (IN) Field group. 
 *     qual_count - (IN) Number of qualifiers on group qset.
 *     f_qual_arr - (IN) Qualifier descriptors array. 
 *     fg        - (IN/OUT)Select code information filled into the group.  
 * 
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_qual_offsets_copy(int unit, _field_group_t *fg, uint16 qual_count,
                         _bcm_field_qual_info_t **f_qual_arr, 
                         uint8 *qual_conf_idx) 
{
    _bcm_field_qual_conf_t *qual_config; /* Qualifier configuration.       */
    _bcm_field_group_qual_t *q_arr;      /* Qualifiers array.              */
    bcm_field_qset_t qset_assigned;      /* Assigned to a specific         */ 
                                         /* entry part qualifiers.         */
    int    qual_idx;                     /* Qualifiers iteration index.    */
    int    part_idx;                     /* Tcam parts iteration index.    */
    int    parts_count;                  /* Number of entry parts.         */
    uint8  conf_idx;                     /* Qualifiers configuration index.*/
    uint8  diff;                         /* Selector diff .                */
    uint16 *qid_arr;                     /* New qualifiers array.          */
    _bcm_field_qual_offset_t *offset_arr;/* New qualifier offsets array.   */
    uint16 size = 0;                     /* Qualifiers array size.         */
    int   rv;                            /* Operation return status.       */  

    /* Input parameters check. */ 
    if ((NULL == fg) || (NULL == f_qual_arr) || (NULL == qual_conf_idx)) {
        return (BCM_E_PARAM);
    }

    BCM_FIELD_QSET_INIT(qset_assigned);
    /* Get number of entry parts we have to read. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Get currently assigned qualifiers. */
    for (part_idx = 0; part_idx < parts_count; part_idx++) {
        q_arr = fg->qual_arr + part_idx;
        for (qual_idx = 0; qual_idx < q_arr->size; qual_idx++) {
            BCM_FIELD_QSET_ADD (qset_assigned, q_arr->qid_arr[qual_idx]);
        }
    }

    for (part_idx = 0; part_idx < parts_count; part_idx++) {
        /* Initialization. */
        offset_arr = NULL;
        qid_arr = NULL;

        /* Get qualifiers array pointer. */
        q_arr = fg->qual_arr + part_idx;
        size = q_arr->size;

        for (qual_idx = 0; qual_idx < qual_count; qual_idx++) {
            /* Check if qualifier was already assigned. */
            if (BCM_FIELD_QSET_TEST (qset_assigned, f_qual_arr[qual_idx]->qid)) {
                continue;
            }

            /* Get qualifier configuration index. */
            conf_idx = qual_conf_idx[qual_idx];
            /* Get qualifier configuration for the index. */
            qual_config = f_qual_arr[qual_idx]->conf_arr + conf_idx;
            /* Test if selector was inserted in a specific tcam part. */
            rv = _field_selector_diff(unit, fg->sel_codes, part_idx, 
                                      &qual_config->selector,
                                      &diff);
            if (BCM_FAILURE(rv) || diff) {
                continue;
            }
            size++;
        }

        /* Allocate qualifiers id and offsets array. */
        _FP_XGS3_ALLOC(qid_arr, (size * sizeof (uint16)), "Group qual id");
        if (NULL == qid_arr) {
            return (BCM_E_MEMORY);
        }
        _FP_XGS3_ALLOC(offset_arr, (size * 
                       sizeof (_bcm_field_qual_offset_t)), "Group qual offset");
        if (NULL == offset_arr) {
            sal_free (qid_arr);
            return (BCM_E_MEMORY);
        }

        /* Copy whatever qualifiers the group already have into the new array */
        if (q_arr->size) {
            sal_memcpy(qid_arr, q_arr->qid_arr, 
                       q_arr->size * sizeof (uint16));
            sal_memcpy(offset_arr, q_arr->offset_arr, 
                       q_arr->size * sizeof(_bcm_field_qual_offset_t));
        }
        size = q_arr->size;

        /* Free old group qualifiers. */
        rv = _bcm_field_group_qualifiers_free(fg, part_idx);
        if (BCM_FAILURE(rv)) {
            sal_free(qid_arr);
            sal_free(offset_arr);
            return (rv);
        }

        /* Now let the group point to the new and bigger array */
        q_arr->qid_arr = qid_arr;
        q_arr->offset_arr = offset_arr;
        q_arr->size = size;

        for (qual_idx = 0; qual_idx < qual_count; qual_idx++) {
            /* Check if qualifier was already assigned. */
            if (BCM_FIELD_QSET_TEST (qset_assigned, f_qual_arr[qual_idx]->qid)) {
                continue;
            }

            /* Get qualifier configuration index. */
            conf_idx = qual_conf_idx[qual_idx];
            /* Get qualifier configuration for the index. */
            qual_config = f_qual_arr[qual_idx]->conf_arr + conf_idx;
            /* Test if selector was inserted in a specific tcam part. */
            rv = _field_selector_diff(unit, fg->sel_codes, part_idx, 
                                      &qual_config->selector,
                                      &diff);
            if (BCM_FAILURE(rv) || diff) {
                continue;
            }
            q_arr->qid_arr[q_arr->size] = f_qual_arr[qual_idx]->qid;
            q_arr->offset_arr[q_arr->size] = qual_config->offset;
            q_arr->size++;
            BCM_FIELD_QSET_ADD (qset_assigned, f_qual_arr[qual_idx]->qid);
        }
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_qual_lists_get
 * Purpose:
 *     Build a group's qual_info_t linked list by assembling
 *     linked-lists from each select code.
 * Parameters:
 *     unit      - (IN) BCM device number.
 *     stage_fc  - (IN) Stage field control structure. 
 *     fg        - (IN) Group control structure.
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_qual_lists_get(int unit, _field_stage_t *stage_fc,
                             _field_group_t *fg)
{
    return (BCM_E_NONE); 
}

/*
 * Function:
 *     _bcm_field_selcode_to_qset
 * Purpose:
 *     Find the qset that corresponds to all the possible qualifiers
 *     supported by the field selection codes (FPF1, FPF2, FPF3).
 * Parameters:
 *     unit      - (IN)  unit
 *     stage_fc  - (IN)  Stage Field control structure.
 *     fg        - (IN)  Field group control structure.
 *     code_id   - (IN)  Entry part.
 *     qset      - (OUT) Client qualifier set.
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_selcode_to_qset(int unit, _field_stage_t *stage_fc, 
                              _field_group_t *fg, int code_id,
                              bcm_field_qset_t *qset)
{
                                /* selectors value.              */ 
    int idx;                    /* Qualifiers array iterator.    */

    /* Input parameters check. */
    if ((NULL == qset) || (NULL == stage_fc) ||
        (NULL == fg)   || (code_id < 0) || (code_id >= _FP_MAX_ENTRY_WIDTH)) {
        return (BCM_E_PARAM); 
    }

    BCM_FIELD_QSET_INIT(*qset);

    for(idx = 0; idx < fg->qual_arr[code_id].size; idx++) {
        BCM_FIELD_QSET_ADD(*qset, fg->qual_arr[code_id].qid_arr[idx]);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *     _bcm_field_selcode_get
 * Purpose:
 *     Finds a 4-tuple of select encodings that will satisfy the
 *     requested qualifier set (Qset).
 * Parameters:
 *     unit      - (IN) BCM unit number.
 *     stage_fc  - (IN) Stage Field control structure.
 *     qset_req  - (IN) Client qualifier set.
 *     fg        - (IN/OUT)Select code information filled into the group.  
 * 
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_selcode_get(int unit, _field_stage_t *stage_fc, 
                           bcm_field_qset_t *qset_req,
                           _field_group_t *fg)
{
    _bcm_field_qual_info_t **f_qual_arr; /* Qualifiers information.         */
    _bcm_field_qual_conf_t *qual_config; /* Qualifier configuration.        */
    uint8 *qual_conf_idx;                /* Array of iterators over each    */
                                         /* individual qual configurations. */
    _field_sel_t *sel_arr;               /* Selectors status before each    */
                                         /* individual qualifier            */
                                         /* configuration was added.        */
    _field_sel_t *candidate;             /* Candidate select codes set.     */
    uint8  conf_idx = 0;                 /* Qualifiers configuration index. */
    uint16 qual_count = 0;               /* Number of qualifiers in         */
                                         /* the requested qset.             */
    int   parts_count = 0;               /* Number of tcam parts.           */
    int   qual_idx = 0;                  /* Qualifiers iteration index.     */
    int   sel_entry_sz = 0;              /* Byte size of sel_arr entity.    */
    int   rv = BCM_E_NONE;               /* Operation return status.        */
 
    /* Input parameters check. */
    if ((NULL == fg) || (NULL == qset_req) || (NULL == stage_fc)) {
        return (BCM_E_PARAM);
    }

    /* Initialization. */
    f_qual_arr = NULL;
    qual_config = NULL;
    qual_conf_idx = NULL;
    sel_arr = NULL;
    candidate = NULL;

    /* Update group selectors based on group flags. */
    rv = _field_group_selectors_init(unit, fg);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifiers configuration.          */
    /* NOTE: Must free f_qual_arr at the end. */
    rv = _field_qualifiers_info_get (unit, stage_fc, qset_req,
                                     &f_qual_arr, &qual_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Allocate and initialize qualifier configurations iterators. */
    _FP_XGS3_ALLOC(qual_conf_idx, (qual_count * sizeof(uint8)),
                   "Field qualifier configuration");
    if (NULL == qual_conf_idx) {
        sal_free(f_qual_arr);
        return (BCM_E_MEMORY);
    }

    /* Get number of entry parts. */
    rv  = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    BCM_IF_ERROR_RETURN(rv);
     
    /* Allocate and initialize select codes status before           */
    /* individual qualifier configuration was applied.              */
    /* Candidate select codes are in the last element of the array. */
    sel_entry_sz = parts_count * sizeof(_field_sel_t);
    _FP_XGS3_ALLOC(sel_arr, ((1 + qual_count) * sel_entry_sz), \
                   "Field group select codes");
    if (NULL == sel_arr) {
        sal_free(qual_conf_idx);
        sal_free(f_qual_arr);
        return (BCM_E_MEMORY);
    }

    /* Initialize first qualifier select codes to group select codes. */
    candidate = sel_arr + (qual_count * parts_count);
    sal_memcpy(candidate, fg->sel_codes, sel_entry_sz);

    /* Initialize first qualifier select codes to a group defaults */
    sal_memcpy(sel_arr, candidate, sel_entry_sz);

    /* Main select codes selection loop over caller requested qualifier set. */
    for (qual_idx = 0; qual_idx < qual_count;) {

        /* Get qualifier selcodes configuration index. */
        conf_idx = qual_conf_idx[qual_idx];

        /*
         * Sort qualifier configurations so minimum
         * change configuration attempted first. 
         */
        if (0 == conf_idx) {
            rv = _field_qual_selectors_sort(unit, candidate,
                    parts_count, f_qual_arr[qual_idx]);
            if (BCM_FAILURE(rv)) {
                sal_free(sel_arr);
                sal_free(qual_conf_idx);
                sal_free(f_qual_arr);
                return (rv);
            }
        }

        /*
         * Set default return value, in case all configuration
         * options were exhausted.
         */
        rv = BCM_E_RESOURCE;

        /* Loop over possible qualifier configurations. */
        for (;conf_idx < f_qual_arr[qual_idx]->conf_sz; conf_idx++)  {

            /* Get qualifier configuration for the index. */
            qual_config = f_qual_arr[qual_idx]->conf_arr + conf_idx;

            /* Skip conflicting configurations. */
            if ((uint8) _FP_INVALID_INDEX == 
                qual_config->selector.update_count) {
               continue;
            }

            /*
             *  Attempt to accommodate specific qualifier
             *  configuration into candidate select codes.
             */
            rv = _field_qual_selectors_insert(unit, candidate,
                                              parts_count,
                                              &qual_config->selector);

            if (BCM_SUCCESS(rv) || (BCM_E_RESOURCE != rv)) {
                break;
            }
        }

        /*
         * If code failed to insert qualifier configuration
         * attempt a previous qualifier in the list using alternative
         * configuration.
         */
        if (BCM_FAILURE(rv)) {
            if ((qual_idx == 0) || (BCM_E_RESOURCE != rv)) {
                break;
            }
            /* Previous qualifier has to use next available configuration. */
            while (qual_idx > 0) {
                /* This qualifier configuration will be re-selected. */
                qual_conf_idx[qual_idx] = 0;
                /* Back to the previous qualifier. */
                qual_idx--;
                /* Check select codes were modified by qualifier. */ 
                qual_config = f_qual_arr[qual_idx]->conf_arr + 
                              qual_conf_idx[qual_idx];
                /* If modified -> reverse changes and proceed to next config.*/
                if ((0 == qual_idx) || 
                    (0 != qual_config->selector.update_count)) {
                    /* Go to the next configuration */
                    qual_conf_idx[qual_idx]++;
                    /* Restore original select codes state. */
                    sal_memcpy(candidate,
                        sel_arr + (qual_idx * parts_count), 
                        sel_entry_sz);
                    break;
                } 
            }
        } else {
            /* Preserve current qualifier configuration index. */
            qual_conf_idx[qual_idx] = conf_idx;
            /* Proceed to the next qualifier. */
            qual_idx++;
            /* Set selection base line for the next qualifier */
            if (qual_idx < qual_count) {
                sal_memcpy(sel_arr + (qual_idx * parts_count),
                           candidate, sel_entry_sz);
            }
        }
    }
    if (BCM_SUCCESS(rv)) {
        /* Copy selected codes to the group configuration. */
        sal_memcpy(fg->sel_codes, candidate, sel_entry_sz);
        /* Copy qualifiers offset to group tcam parts. */
        rv = _field_qual_offsets_copy(unit, fg, qual_count,
                                      f_qual_arr, qual_conf_idx);
    }
    sal_free(sel_arr);
    sal_free(qual_conf_idx);
    sal_free(f_qual_arr);
    return (rv);
}
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
/*
 * Function:
 *     _field_egress_key_attempt
 * Purpose:
 *     Verify if specific key can satisfy user requested qset. 
 *     
 * Parameters:
 *     unit      - (IN) BCM unit number.
 *     stage_fc  - (IN) Stage Field control structure.
 *     qset_req  - (IN) Client qualifier set.
 *     key_pri   - (IN) Primary key id.
 *     key_sec   - (IN) Secondary key id.
 *     fg        - (IN/OUT)Select code information filled into the group.  
 * 
 * Returns:
 *     BCM_E_XXX
 */
int
_bcm_field_egress_key_attempt(int unit, _field_stage_t *stage_fc, 
                              bcm_field_qset_t *qset_req,
                              uint8 key_pri, uint8 key_sec,
                              _field_group_t *fg)
{
    /* Input parameters check. */
    if ((NULL == fg) || (NULL == qset_req) || (NULL == stage_fc)) {
        return (BCM_E_PARAM);
    }
    fg->sel_codes[0].fpf3= key_pri; 
    if (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
        fg->sel_codes[1].fpf3= key_sec; 
    }
    /* Verify that each requested qualifier present in the key. */
    return _bcm_field_selcode_get(unit, stage_fc, qset_req, fg);
}
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */

/*
 * Function: _field_qualify_VlanFormat
 *
 * Purpose:
 *     Add qualification data to an entry for Vlan Tag Format.
 *
 * Parameters:
 *     unit     - (IN) BCM unit number.
 *     entry    - (IN) Entry ID.
 *     qual_id  - (IN) Qualifier id. 
 *     data     - (IN) Outer & Inner tag presence info.
 *     mask     - (IN) Data mask.
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_qualify_VlanFormat(int unit, bcm_field_entry_t entry,
                          bcm_field_qualify_t qual_id,
                          uint8 data, uint8 mask)
{
    _field_entry_t      *f_ent;  /* Field entry structure.       */
    int                 rv;      /* Operation return status. */

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        return (rv);
    }

#ifdef BCM_TRX_SUPPORT
    {
        _field_action_t *fa;
        
        for (fa = f_ent->actions; fa; ) {
            switch (fa->action) {
            case bcmFieldActionOuterVlanCopyInner:
            case bcmFieldActionOuterVlanPrioCopyInner:
            case bcmFieldActionOuterVlanCfiCopyInner:
            case bcmFieldActionInnerVlanCopyOuter:
            case bcmFieldActionInnerVlanPrioCopyOuter:
            case bcmFieldActionInnerVlanCfiCopyOuter:
                /* If any of these actions are defined, the VLAN format must be
                   double-tagged */

                if (!_bcm_field_trx_vlan_format_qualify_is_double_tagged(data, mask)) {
                    return (BCM_E_PARAM);
                }

                fa = 0;
            
                break;

            default:
                fa = fa->next;
            }
        }
    }
#endif /* BCM_TRX_SUPPORT */

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (soc_feature(unit, soc_feature_field_multi_stage)) {
        if ((_BCM_FIELD_STAGE_INGRESS != f_ent->group->stage_id) ||
            (SOC_IS_TRX(unit))) {
            data = (((data & 0x2) >> 1) | ((data & 0x1) << 1)); 
            mask = (((mask & 0x2) >> 1) | ((mask & 0x1) << 1)); 
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */

    rv = _field_qualify32(unit, entry, qual_id, data, mask);
    return (rv);
}

/*
 * Function: _field_qualify_VlanFormat_get
 *
 * Purpose:
 *     Get qualification match criteria from an entry for Vlan Tag Format.
 *
 * Parameters:
 *     unit     - (IN) BCM unit number.
 *     entry    - (IN) Entry ID.
 *     qual_id  - (IN) Qualifier id. 
 *     data     - (OUT) Outer & Inner tag presence info.
 *     mask     - (OUT) Data mask.
 * Returns:
 *     BCM_E_XXX
 */
int
_field_qualify_VlanFormat_get(int unit, bcm_field_entry_t entry,
                          bcm_field_qualify_t qual_id,
                          uint8 *data, uint8 *mask)
{
    uint8            hw_data;   /* HW encoded data.         */
    uint8            hw_mask;   /* HW encoded mask.         */
    int              rv;        /* Operation return status. */
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    _field_entry_t   *f_ent;    /* Field entry structure.   */
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */


    /* Read qualifier match value and mask. */
    rv = _bcm_field_entry_qualifier_uint8_get(unit, entry, qual_id,
                                          &hw_data, &hw_mask);
    BCM_IF_ERROR_RETURN(rv);

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (BCM_SUCCESS(rv)) {
        rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
        BCM_IF_ERROR_RETURN(rv);

        if (soc_feature(unit, soc_feature_field_multi_stage)) {
            if ((_BCM_FIELD_STAGE_INGRESS != f_ent->group->stage_id) ||
                (SOC_IS_TRX(unit))) {
                *data = (((hw_data & 0x2) >> 1) | ((hw_data & 0x1) << 1)); 
                *mask = (((hw_mask & 0x2) >> 1) | ((hw_mask & 0x1) << 1)); 
            } else {
                *data = hw_data;
                *mask = hw_mask;
            }
        } else {
            *data = hw_data;
            *mask = hw_mask;
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    return (rv);
}

#if defined (BROADCOM_DEBUG)
/*
 * Function:
 *     _field_range_dump
 *
 * Purpose:
 *     Show contents of a range checker
 *
 * Parameters:
 *     fr - range checker structure pointer
 *
 * Returns:
 *     Nothing.
 */
STATIC void
_field_range_dump(const char *pfx, _field_range_t *fr)
{
    FP_SHOW(("%s: Range ID=%d, flag=%#x, min=%d, max=%d, hw_index=%d(%#x), ",
                 pfx, fr->rid, fr->flags, fr->min, fr->max, fr->hw_index,
                 fr->hw_index));
    if (fr->style == _FP_RANGE_STYLE_EASYRIDER) {
        FP_SHOW(("style=BCM56601\n"));
    } else {
        FP_SHOW(("style=BCM56504\n"));
    }
}

/*
 * Function:
 *     _field_entry_phys_dump
 *
 * Purpose:
 *     Show contents of a physical entry structure
 *
 * Parameters:
 *     unit       - BCM device number
 *     f_ent      - Physical entry to dump
 *     entry_part - Field entry part.
 * Returns:
 *     Nothing.
 */
STATIC void
_field_entry_phys_dump(int unit, _field_entry_t *f_ent, uint8 entry_part)
{
    _bcm_field_group_qual_t   *q_arr;  /* Qualifiers array.    */
    int                       idx;
    int                       idx_max;
    int                       qual_idx;
    int                       free_tcam = FALSE;
    _field_group_t            *fg;
    _bcm_field_qual_data_t    q_data;
    _bcm_field_qual_data_t    q_mask;
    _bcm_field_qual_offset_t  *q_offset;
    char                      *ip_type_str[] = BCM_FIELD_IPTYPE_STRINGS;
    int                       rv;
#if defined(BCM_TRX_SUPPORT)
    int                       range_check_valid = 0;
#endif /* !BCM_TRX_SUPPORT */

    FP_SHOW(("         slice=%d, slice_idx=%#x, part =%d prio=%#x, flags=%#x, ",
             f_ent->fs->slice_number, f_ent->slice_idx, entry_part, 
             f_ent->prio, f_ent->flags));
    if (!(f_ent->flags & _FP_ENTRY_INSTALLED)) {
        FP_SHOW(("Not installed\n"));
    } else {
        FP_SHOW(("Installed\n"));
    }
    
    if ((NULL == f_ent->tcam.key)) {
        free_tcam = TRUE;
    }

    rv = _bcm_field_qual_tcam_key_mask_get(unit, f_ent);
    if (BCM_FAILURE(rv)) {
        FP_SHOW(("\nUnit (%d) Entry (%d) tcam key read failure.\n", 
                 unit, f_ent->eid));
        return;
    } 

    FP_SHOW(("              tcam: color_indep=%d, ", 
             f_ent->flags & _FP_ENTRY_COLOR_INDEPENDENT));



    fg = f_ent->group;
    q_arr = fg->qual_arr + entry_part;
    for (qual_idx = 0; qual_idx < q_arr->size; qual_idx++) {
        idx_max = -1;
        q_offset = q_arr->offset_arr + qual_idx;

        /* There is no value associated with zero width qualifiers (Stage, Ip4 etc)
           just print the name. 
         */
        if ((0 == q_offset->width) && (0 == q_offset->width1) &&
            (0 == q_offset->width2)) {
            switch (q_arr->qid_arr[qual_idx]) {
                case bcmFieldQualifyInPorts:
                case bcmFieldQualifyInPort:
#if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_TRX_SUPPORT)                
                    if (BCM_PBMP_NOT_NULL(f_ent->pbmp.mask)) {
                        char                      pfmt[SOC_PBMP_FMT_LEN];
                        
                        /* Remove loopback port from ipbm mask */
                        if (soc_feature(unit, soc_feature_internal_loopback)) {
                            BCM_PBMP_REMOVE(f_ent->pbmp.mask, PBMP_LB(unit));
                        }

                        FP_SHOW(("\n %s ", 
                                 _field_qual_name(q_arr->qid_arr[qual_idx])));
                        FP_SHOW(("\n    DATA="));
                        FP_SHOW(("%s", SOC_PBMP_FMT(f_ent->pbmp.data, pfmt)));
                        FP_SHOW(("\n    MASK="));
                        FP_SHOW(("%s", SOC_PBMP_FMT(f_ent->pbmp.mask, pfmt)));
                    }
#endif
                    break;
                case bcmFieldQualifyHiGig:
                    if (f_ent->tcam.higig_mask) {
                        FP_SHOW(("\n %s ", 
                                 _field_qual_name(q_arr->qid_arr[qual_idx])));
                        FP_SHOW(("\n    DATA= %d", f_ent->tcam.higig));
                        FP_SHOW(("\n    MASK= %d", f_ent->tcam.higig_mask));
                    }
                    break;
                case bcmFieldQualifyIpType:
                    if ((bcmFieldIpTypeAny != f_ent->tcam.ip_type) && 
                            (bcmFieldIpTypeCount > f_ent->tcam.ip_type)) {
                        FP_SHOW(("\n %s ", 
                                 _field_qual_name(q_arr->qid_arr[qual_idx])));
                        FP_SHOW(("\n    DATA= %s", 
                                  ip_type_str[f_ent->tcam.ip_type]));
                    } 
                    break;
                default:
                    FP_SHOW(("\n %s ", _field_qual_name(q_arr->qid_arr[qual_idx])));
            }
            continue;
        } else {
#if defined(BCM_FIREBOLT2_SUPPORT)
            /* 
             * Although FB2 has drop qualifier - 
             * Drop bit is always present in the tcam 
             * ancestor of the fixed key. 
             */
            if ((bcmFieldQualifyDrop == q_arr->qid_arr[qual_idx]) &&
                (SOC_IS_FIREBOLT2(unit))) {
                if (f_ent->tcam.drop_mask) {
                    FP_SHOW(("\n %s ", 
                                _field_qual_name(q_arr->qid_arr[qual_idx])));
                    FP_SHOW(("\n    DATA= %d", f_ent->tcam.drop));
                    FP_SHOW(("\n    MASK= %d", f_ent->tcam.drop_mask));
                }
                continue;
            }
#endif /* BCM_FIREBOLT2_SUPPORT */
        }

        _FP_QUAL_DATA_CLEAR(q_data);
        _FP_QUAL_DATA_CLEAR(q_mask);
        /* Read qualifier match value and mask. */
        rv = _bcm_field_qual_value_get(unit, q_offset, f_ent, q_data, q_mask);
        if (BCM_FAILURE(rv)) {
            return;
        } 

        /* Check if qualifier was installed. */
        for (idx = 3; idx >= 0; idx--) {
            if (q_mask[idx] != 0)  {
                idx_max = idx;
                break;
            }
        }
 
#if defined(BCM_TRX_SUPPORT)
        if ((bcmFieldQualifyRangeCheck == q_arr->qid_arr[qual_idx]) &&
            (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyInterfaceClassPort) ||
             BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyInterfaceClassL3) ||
             BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyInterfaceClassL2))) {
            for (idx = idx_max; idx >= 0; idx--) {
                if (0 != (q_mask[idx] & 0xffffff)) {
                    range_check_valid = 1;
                }
            }
            if (0 == range_check_valid) {
                continue;
            }
        }
#endif /* !BCM_TRX_SUPPORT */
      
        if (idx_max >= 0) {
            FP_SHOW(("\n %s ", _field_qual_name(q_arr->qid_arr[qual_idx])));
            FP_SHOW(("\n    Offset: %d Width: %d ", q_offset->offset,
                     q_offset->width));
            if (0 != q_offset->width1) {
                FP_SHOW(("\n    Offset1: %d Width1: %d ", q_offset->offset1,
                         q_offset->width1));
            }
            if (0 != q_offset->width2) {
                FP_SHOW(("\n    Offset2: %d Width2: %d ", q_offset->offset2,
                         q_offset->width2));
            }
            FP_SHOW(("\n    DATA=0x"));
            for (idx = idx_max; idx >= 0; idx--) {
                FP_SHOW(("%08x ", q_data[idx]));
            }
            FP_SHOW(("\n    MASK=0x"));
            for (idx = idx_max; idx >= 0; idx--) {
                FP_SHOW(("%08x ", q_mask[idx]));
            }
        }
    }

    if (free_tcam) {
        if (NULL != f_ent->tcam.key) {
            sal_free(f_ent->tcam.key);
            sal_free(f_ent->tcam.mask);
        }
        if (f_ent->flags & _FP_ENTRY_USES_IPBM_OVERLAY) {
            if (NULL != f_ent->extra_tcam.key) {
                sal_free(f_ent->extra_tcam.key);
                sal_free(f_ent->extra_tcam.mask);
            }
        }
        f_ent->tcam.key = f_ent->tcam.mask =
            f_ent->extra_tcam.key = f_ent->extra_tcam.mask = NULL;
        free_tcam = FALSE;
    }

    FP_SHOW(("\n"));
}


/*
 * Function:
 *     _field_selcode_dump
 * Purpose:
 *     Output a set of field selects code.
 */
void
_field_selcode_dump(int unit, char *prefix, _field_sel_t *sel_codes,
                    char *suffix)
{
    if (NULL == sel_codes) {
        return;
    }
    
    FP_SHOW(("%s{", (prefix == NULL) ? "" : prefix));
#ifdef BCM_EASYRIDER_SUPPORT
    if (SOC_IS_EASYRIDER(unit)) {
        if (_FP_SELCODE_DONT_CARE != sel_codes->fpf0) { 
            FP_SHOW(("\n         FPF0=%d", sel_codes->fpf0));
        }
    }
#endif /* BCM_EASYRIDER_SUPPORT */
    if (_FP_SELCODE_DONT_CARE != sel_codes->fpf1) { 
        FP_SHOW(("\n         FPF1=%d", sel_codes->fpf1));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->fpf2) { 
        FP_SHOW(("\n         FPF2=%d", sel_codes->fpf2));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->fpf3) { 
        FP_SHOW(("\n         FPF3=%d", sel_codes->fpf3));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->fpf4) { 
        FP_SHOW(("\n         FPF4=%d", sel_codes->fpf4));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->src_class_sel) { 
        FP_SHOW(("\n         SourceClassSelect=%d", sel_codes->src_class_sel));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->dst_class_sel) { 
        FP_SHOW(("\n         DestinationClassSelect=%d", sel_codes->dst_class_sel));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->intf_class_sel) {
        FP_SHOW(("\n         InterfaceClassSelect=%d", sel_codes->intf_class_sel));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->loopback_type_sel) {
        FP_SHOW(("\n         LoopbackTypeSelect=%d", sel_codes->loopback_type_sel));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->ingress_entity_sel) {
        FP_SHOW(("\n         IngressEntitySelect=%d",
                 sel_codes->ingress_entity_sel));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->src_entity_sel) {
        FP_SHOW(("\n         SrcEntitySelect=%d",
                 sel_codes->src_entity_sel));    }

    if (_FP_SELCODE_DONT_CARE != sel_codes->dst_fwd_entity_sel) {
        FP_SHOW(("\n         DestinationEntitySelect=%d",
                 sel_codes->dst_fwd_entity_sel));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->fwd_field_sel) {
        FP_SHOW(("\n         ForwardingFieldSelect=%d",
                 sel_codes->fwd_field_sel));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->ip_header_sel) {
        FP_SHOW(("\n         IpHeaderSelect=%s", (sel_codes->ip_header_sel) ?
                 "Inner" : "Outer"));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->inner_vlan_overlay) {
        FP_SHOW(("\n         InnerVlanOverlaySelect=%d", sel_codes->inner_vlan_overlay));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->aux_tag_1_sel) {
        FP_SHOW(("\n         AuxTag1Select=%d", sel_codes->aux_tag_1_sel));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->aux_tag_2_sel) {
        FP_SHOW(("\n         AuxTag2Select=%d", sel_codes->aux_tag_2_sel));
    }
    if (_FP_SELCODE_DONT_CARE != sel_codes->intraslice) {
        if (_FP_SELCODE_DONT_USE == sel_codes->intraslice) {
            FP_SHOW(("\n         Intraslice=%s\n", "Primary slice."));
        } else {
            FP_SHOW(("\n         Intraslice=%d\n", sel_codes->intraslice));
        }
    }
    return;
}


/*
 * Function:
 *     _field_slice_dump
 * Purpose:
 *     Output a slice worth of data, including any entries in the slice.
 */
STATIC void 
_field_slice_dump(int unit, char *prefix, _field_slice_t *fs, char *suffix)
{
    char                buf[SOC_PBMP_FMT_LEN];

    FP_SHOW(("%s{", (prefix == NULL) ? "" : prefix));
    FP_SHOW(("slice_number=%d, ", fs->slice_number));
    FP_SHOW(("Entry count=%d(%#x),", fs->entry_count, fs->entry_count));
    FP_SHOW(("pbmp={%s}", SOC_PBMP_FMT(fs->pbmp, buf)));
    FP_SHOW(("},%s", (suffix == NULL) ? "" : suffix));
}

/*
 * Function:
 *     _field_qual_list_dump
 * Purpose:
 *     Output qualiers set in 'qset'.
 */
STATIC void
_field_qual_list_dump(char *prefix, _field_group_t *fg, uint8 entry_part, char *suffix)
{
    
    _bcm_field_group_qual_t *q_arr;   /* Qualifiers array.        */
    int first_print = 1;
    int idx;

    FP_SHOW(("%s{", (prefix == NULL) ? "" : prefix));
    FP_SHOW(("\n"));
    q_arr = fg->qual_arr + entry_part; 
    /* Output the qualifier info list*/
    for (idx = 0; idx < q_arr->size; idx++) {
        FP_SHOW(("%s%s", 
                     (first_print ? "" : "->"), 
                     _field_qual_name(q_arr->qid_arr[idx])));
        first_print = 0;
    }
    FP_SHOW(("}%s", (suffix == NULL) ? "" : suffix));
}

/*
 * Function:
 *     _field_qset_dump
 * Purpose:
 *     Output qualiers set in 'qset'.
 */
void
_field_qset_dump(char *prefix, bcm_field_qset_t qset, char *suffix)
{
    int                 qual;
    int                 idx;
    int first_qual = 1, first_udf_id = 1;

    if (prefix == NULL) {
        prefix = "";
    }
    if (suffix == NULL) {
        suffix = "";
    }

    FP_SHOW(("%s{", prefix));
    for (qual = 0; qual < _bcmFieldQualifyCount; qual++) {
        if (BCM_FIELD_QSET_TEST(qset, qual)) {
            FP_SHOW(("%s%s", (first_qual ? "" : ", "), 
                     _field_qual_name(qual)));
            first_qual = 0;
        }
    }

    for (idx = 0; idx < BCM_FIELD_USER_NUM_UDFS; idx++) {
        if (!SHR_BITGET(qset.udf_map, idx)) {
            continue;
        }
        FP_SHOW(("%s%d", (first_udf_id ? " : udf_id={" : ", "), idx));
        first_udf_id = 0;
    }
    if (first_udf_id == 0) {
        FP_SHOW(("}"));
    }

    FP_SHOW(("}%s", suffix));
}

/*
 * Function:
 *     _field_qset_debug
 * Purpose:
 *     Output qualier set in 'qset' for debug mode only.
 */
void
_field_qset_debug(bcm_field_qset_t qset)
{
    int qual;
    int first_qual = 1;

    FP_VERB(("{"));
    for (qual = 0; qual < _bcmFieldQualifyCount; qual++) {
        if (BCM_FIELD_QSET_TEST(qset, qual)) {
            FP_VERB(("%s%s", (first_qual ? "" : ", "), 
                         _field_qual_name(qual)));
            first_qual = 0;
        }
    }
    FP_VERB(("}"));
}

/*
 * Function:
 *     _field_counter_dump
 * Purpose:
 *     Output fields in a _field_counter_s struct.
 */
STATIC int
_field_stat_dump(int unit, const _field_entry_t *f_ent)
{
    _field_stat_t        *f_st;
    int                  idx;
    int                  rv = BCM_E_NONE;
    char                 *sname[] = BCM_FIELD_STAT;
    char                 *_sname[] = _BCM_FIELD_STAT;

    /* Input parameters check. */
    if (f_ent == NULL) {
        return (BCM_E_PARAM); 
    }

    if (f_ent->statistic.flags  & _FP_ENTRY_STAT_VALID) {
        rv = _bcm_field_stat_get (unit, f_ent->statistic.sid, &f_st);  
        if (BCM_FAILURE(rv)) {
            return (rv);
        }

        FP_SHOW(("{stat id %d  slice = %d idx=%d entries=%d}", f_st->sid, 
                 f_st->pool_index, f_st->hw_index, f_st->hw_entry_count));
        for (idx = 0; idx < f_st->nstat; idx++) { 
            if (f_st->stat_arr[idx] < bcmFieldStatCount) {
                FP_SHOW(("{%s}", sname[f_st->stat_arr[idx]]));
            } else {
                if ((f_ent->statistic.flags  & _FP_ENTRY_STAT_USE_EVEN) && 
                    (0 != (idx & 0x1))) {
                    continue;
                }
                if ((f_ent->statistic.flags  & _FP_ENTRY_STAT_USE_ODD) && 
                    (0 == (idx & 0x1))) {
                    continue;
                }
                FP_SHOW(("{%s}", _sname[f_st->stat_arr[idx] - bcmFieldStatCount]));
            }
        }
    } else {
        FP_SHOW(("NULL"));
    }
    return (rv);
}

/*
 * Function:
 *     _field_policers_dump
 * Purpose:

 *     Output meter data for given entry.
 */
STATIC void
_field_policers_dump(int unit, _field_entry_t *f_ent)
{
    bcm_policer_t     policer_id;   /* Policer id.                  */
    _field_policer_t  *f_pl;        /* Internal policer descriptor. */
    int               idx;          /* Policers levels iterator.    */
    int               rv;           /* Operation return status.     */

    for (idx = 0; idx < _FP_POLICER_LEVEL_COUNT; idx++) {
        /* Read policer id from entry. */
        rv = bcm_esw_field_entry_policer_get(unit, f_ent->eid, 
                                             idx, &policer_id);
        if (BCM_E_NOT_FOUND == rv) {
            continue;
        }
        if (BCM_FAILURE(rv)) {
            return;
        }

        /* Get policer reference count. */
        rv = _bcm_field_policer_get(unit, policer_id, &f_pl);
        if (BCM_FAILURE(rv)) {
            return;
        }
        FP_SHOW(("{"));

        if (bcmPolicerModeCommitted != f_pl->cfg.mode) {
            FP_SHOW(("peak_kbits_sec=%#x, peak_kbits_burst=%#x,",
                         f_pl->cfg.pkbits_sec, f_pl->cfg.pkbits_burst));
        } 
        if (bcmPolicerModePeak != f_pl->cfg.mode) {
            FP_SHOW((" commit_kbits_sec=%#x, commit_kbits_burst=%#x, ",
                         f_pl->cfg.ckbits_sec, f_pl->cfg.ckbits_burst));
        }

        FP_SHOW((" mode=%#x, entries=%d, %s}",
                 f_pl->cfg.mode, f_pl->sw_ref_count,
                 (f_pl->hw_flags & _FP_POLICER_DIRTY) ? "Dirty" : "Clean"));
    }
}

/*
 * Function:
 *     _field_action_dump
 * Purpose:
 *     Output fields in a _field_action_s struct.
 */
STATIC void
_field_action_dump(const _field_action_t *fa)
{
    if (fa == NULL) {
        FP_SHOW(("NULL"));
    } else {
        FP_SHOW(("{act=%s, param0=%d(%#x), param1=%d(%#x)}, param2=%d(%#x), param3=%d(%#x),",
                     _field_action_name(fa->action), fa->param[0], fa->param[0],
                     fa->param[1], fa->param[1], fa->param[2], fa->param[2],
                     fa->param[3], fa->param[3]));
    }
}

/*
 * Function:
 *     _field_group_status_dump
 * Purpose:
 *     Output the fields in a bcm_field_group_status_s struct.
 */
STATIC void
_field_group_status_dump(const bcm_field_group_status_t *gstat)
{
    FP_SHOW(("{prio_min=%d,",       gstat->prio_min));
    FP_SHOW((" prio_max=%d,",       gstat->prio_max));
    FP_SHOW((" entries_total=%d,",  gstat->entries_total));
    FP_SHOW((" entries_free=%d,",   gstat->entries_free));
    FP_SHOW(("\n                      "));
    FP_SHOW((" counters_total=%d,", gstat->counters_total));
    FP_SHOW((" counters_free=%d,",  gstat->counters_free));
    FP_SHOW((" meters_total=%d,",   gstat->meters_total));
    FP_SHOW((" meters_free=%d}",    gstat->meters_free));
}


#endif /* BROADCOM_DEBUG */

/*
 * Function: bcm_esw_field_init
 *
 * Purpose:
 *    Initialize field module.
 *
 * Parameters:
 *     unit - (IN) BCM device number
 *
 * Returns:
 *     BCM_E_UNIT    - Invalid BCM unit number.
 *     BCM_E_UNAVAIL - Field Processor not on device.
 *     BCM_E_MEMORY  - Allocation failure
 *     BCM_E_XXX     - Error code from bcm_XX_field_init()
 *     BCM_E_NONE    - Success
 */
int
bcm_esw_field_init(int unit)
{
    int                udf_idx;    /* Iteration index.         */
    int                rv;         /* Operation return value.  */
    _field_control_t   *fc = NULL; /* Field control structure. */
#ifdef BCM_WARM_BOOT_SUPPORT
    _field_stage_id_t  stage_id;
    _field_stage_t     *stage_fc;
     int               stable_size;
     uint32            alloc_get;
     soc_scache_handle_t handle;
#endif /* BCM_WARM_BOOT_SUPPORT */

    /* Make sure the Unit can support this module. */
    if (SOC_IS_SHADOW(unit) || !soc_feature(unit, soc_feature_field)) {
        FP_ERR(("FP(unit %d) Error: No Field Processor available \n", unit));
        return (BCM_E_UNAVAIL);
    }

    /* Detatch first if it's been previously initialized. */
    if (_field_control[unit] != NULL) {
        _field_control[unit]->init = FALSE;
        rv = bcm_esw_field_detach(unit);
        if (BCM_FAILURE(rv)) {
            FP_ERR(("FP(unit %d) Error: Module deinit failed.\n", unit));
            return (rv);
        }
    }

    /* Allocate a bcm_field_control */
    _FP_XGS3_ALLOC(fc, sizeof (_field_control_t), "field_control");
    if (NULL == fc) {
        return (BCM_E_MEMORY);
    }

#if defined(BCM_TRIUMPH_SUPPORT)  
    /* First check if external FP is present. */
    if ((soc_feature(unit, soc_feature_esm_support)) &&
        (SOC_MEM_IS_VALID(unit, EXT_FP_CNTRm)) &&
        (soc_mem_index_count(unit, EXT_FP_CNTRm))) {
        fc->flags |= _FP_EXTERNAL_PRESENT;
    }
#endif /* BCM_TRIUMPH_SUPPORT */

    /* Allocate policer lookup hash. */
    _FP_XGS3_ALLOC(fc->policer_hash, _FP_HASH_SZ(fc) * \
                   sizeof(_field_policer_t *), "Policer hash");
    if (NULL == fc->policer_hash) {
        _field_control_free(unit, fc);
        return (BCM_E_MEMORY);
    }

    /* Allocate statistics collection lookup hash. */
    _FP_XGS3_ALLOC(fc->stat_hash, _FP_HASH_SZ(fc) * \
                   sizeof(_field_stat_t *), "Stat hash");
    if (NULL == fc->stat_hash) {
        _field_control_free(unit, fc);
        return (BCM_E_MEMORY);
    }

    /* Allocate user defined qualifiers. */
    _FP_XGS3_ALLOC(fc->udf, BCM_FIELD_USER_NUM_UDFS * \
                   sizeof(_field_udf_t), "Udf table");
    if (NULL == fc->udf) {
        _field_control_free(unit, fc);
        return (BCM_E_MEMORY);
    }

    /* Create protection mutex. */
    fc->fc_lock = sal_mutex_create("field_control.lock");
    if (fc->fc_lock == NULL) {
        _field_control_free(unit, fc);
        return (BCM_E_MEMORY);
    }

    /* Initialize pipeline stages field control structures. */
    rv = _field_stages_init(unit, fc);
    if (BCM_FAILURE(rv)) {
        _field_control_free(unit, fc);
        return rv;
    }

    /* Initialize fp status structure. */
    fc->stage       = bcmFieldStageDefault;

    if (soc_feature(unit, soc_feature_field_intraslice_double_wide)) {
        fc->flags |= _FP_INTRASLICE_ENABLE;
    }

    /* Assign the virtual UDFs to the underlying H/W */
    for (udf_idx = 0; udf_idx < BCM_FIELD_USER_NUM_UDFS; udf_idx++) {
        fc->udf[udf_idx].udf_num = udf_idx >> 2;
        fc->udf[udf_idx].user_num = udf_idx & 0x03;
    }

    /* Initialize the field select offset tables */
#ifdef BCM_EASYRIDER_SUPPORT
    if (SOC_IS_EASYRIDER(unit)) {
        rv = _bcm_field_er_init(unit, fc);
    } else 
#endif /* BCM_EASYRIDER_SUPPORT */

#if defined(BCM_RAPTOR_SUPPORT)
    if (SOC_IS_RAPTOR(unit) || SOC_IS_RAVEN(unit) || SOC_IS_HAWKEYE(unit)) {
        rv = _bcm_field_raptor_init(unit, fc);
    } else
#endif /* BCM_RAPTOR_SUPPORT */

#if defined(BCM_TRIUMPH_SUPPORT)
    if (SOC_IS_TR_VL(unit)) {
#if defined(BCM_TRIDENT_SUPPORT)
        if (SOC_IS_TD_TT(unit)) {
            rv = _bcm_field_trident_init(unit, fc);
        } else 
#endif /* BCM_TRIDENT_SUPPORT */
#if defined(BCM_TRIUMPH2_SUPPORT)
        if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 
            SOC_IS_VALKYRIE2(unit)) {
            rv = _bcm_field_tr2_init(unit, fc);
        } else 
#endif /* BCM_TRIUMPH2_SUPPORT */
#if defined(BCM_ENDURO_SUPPORT)
        if (SOC_IS_ENDURO(unit)) {
            rv = _bcm_field_en_init(unit, fc);
        } else 
#endif /* BCM_ENDURO_SUPPORT */
#if defined(BCM_HURRICANE_SUPPORT)
        if (SOC_IS_HURRICANE(unit)) {
            rv = _bcm_field_hu_init(unit, fc);
        } else 
#endif /* BCM_HURRICANE_SUPPORT */
#if defined(BCM_KATANA_SUPPORT)
        if (SOC_IS_KATANA(unit)) {
            rv = _bcm_field_katana_init(unit, fc);
        } else 
#endif /* BCM_KATANA_SUPPORT */
        {
            rv = _bcm_field_tr_init(unit, fc);
        }
    } else
#endif /* BCM_TRIUMPH_SUPPORT */    

#if defined(BCM_SCORPION_SUPPORT)
    if (SOC_IS_SC_CQ(unit)) {
        rv = _bcm_field_sc_init(unit, fc);
    } else
#endif /* BCM_TRIUMPH_SUPPORT */    

#ifdef BCM_FIREBOLT_SUPPORT
    if (SOC_IS_FBX(unit)) {
        rv = _bcm_field_fb_init(unit, fc);
    }
#endif /* BCM_FIREBOLT_SUPPORT */


    /* cleanup on FB init failure.  */
    if (BCM_FAILURE(rv)) {
        _field_stages_destroy(unit, fc);
        _field_control_free(unit, fc);
        return rv;
    }

    /* Initialize supported qset for each stage. */       
    _field_stages_supported_qset_init(unit, fc);

    last_allocated_eid = 0;
    _field_control[unit] = fc;

    /* Register counter collection callback. */
    soc_counter_extra_register(unit, _bcm_esw_fp_counters_collect);

#ifdef BCM_WARM_BOOT_SUPPORT
    if (NULL == fc->scache_ptr) {
        SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
        SOC_SCACHE_HANDLE_SET(handle, unit, BCM_MODULE_FIELD, 0);
        if ((stable_size > 0) && !SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
            if (SOC_IS_TRX(unit)) {
                fc->scache_size = 150 * 1024;
            } else {
                /* Allocate a section of the Level 2 Warm Boot
                 * global cache.
                 * Assume 90% of the total stable size - just a heuristic
                 */
                fc->scache_size = (9 * stable_size) / 10;
            }

            /* Get the pointer for the Level 2 cache */
            rv = soc_scache_ptr_get(unit, handle, 
                                    &(fc->scache_ptr), &alloc_get);
            if (!SOC_WARM_BOOT(unit) && (SOC_E_NOT_FOUND == rv)) {
                /* Not yet allocated in Cold Boot */
                SOC_IF_ERROR_RETURN
                    (soc_scache_alloc(unit, handle, fc->scache_size + 
                                      SOC_WB_SCACHE_CONTROL_SIZE));
                rv = soc_scache_ptr_get(unit, handle, 
                                        &(fc->scache_ptr), &alloc_get);
            }

            if (BCM_FAILURE(rv)) {
                return rv;
            } else if (alloc_get != fc->scache_size + 
                                    SOC_WB_SCACHE_CONTROL_SIZE) {
                /* Expected size doesn't match retrieved size */
                return BCM_E_INTERNAL;
            } else if (NULL == fc->scache_ptr) {
                return BCM_E_MEMORY;
            }
        }
    }

    /* Construct the _field_stage_t structure based on HW programming 
     * in Warm Boot mode */
    if (SOC_WARM_BOOT(unit)) {
        fc->l2warm = (fc->scache_size && 
                      !SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) ? 1 : 0;        

        if (SOC_IS_FIREBOLT(unit) || SOC_IS_HB_GW(unit)) {
            stage_id = _BCM_FIELD_STAGE_INGRESS;

            BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, stage_id,
                &stage_fc));

            rv = _field_fb_stage_reinit(unit, fc, stage_fc);
            if ((rv == BCM_E_INTERNAL) && (fc->scache_size > 0) && 
                (fc->l2warm == 0)) {
                /* Stale scache */
                SOC_IF_ERROR_RETURN
                    (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR, 
                                        SOC_STABLE_STALE, SOC_STABLE_FIELD, 0));
                /* Clean up generated state and restart as Level 1 */
                BCM_IF_ERROR_RETURN(_field_state_cleanup(unit, fc));
                rv = _field_fb_stage_reinit(unit, fc, stage_fc);
            }
        } else if (SOC_IS_RAVEN(unit) || SOC_IS_HAWKEYE(unit)) {
#ifdef BCM_RAVEN_SUPPORT
            stage_id = _BCM_FIELD_STAGE_INGRESS;
            BCM_IF_ERROR_RETURN
                (_field_stage_control_get(unit, stage_id, &stage_fc));
            rv = _field_raven_stage_reinit(unit, fc, stage_fc);
            if ((rv == BCM_E_INTERNAL) && (fc->scache_size > 0) && 
                (fc->l2warm == 0)) {
                /* Stale scache */
                SOC_IF_ERROR_RETURN
                    (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR, 
                                        SOC_STABLE_STALE, SOC_STABLE_FIELD, 0));
                /* Clean up generated state and restart as Level 1 */
                BCM_IF_ERROR_RETURN(_field_state_cleanup(unit, fc));
                rv = _field_raven_stage_reinit(unit, fc, stage_fc);
            }
#endif
        } else if (SOC_IS_FIREBOLT2(unit)) {
#ifdef BCM_FIREBOLT2_SUPPORT
            uint8 oldl2warm = 0;
            stage_id = _BCM_FIELD_STAGE_INGRESS;
            BCM_IF_ERROR_RETURN
                (_field_stage_control_get(unit, stage_id, &stage_fc));
            rv = _field_fb2_stage_ingress_reinit(unit, fc, stage_fc);
            if ((rv == BCM_E_INTERNAL) && (fc->scache_size > 0) && 
                (fc->l2warm == 0)) {
                /* Stale scache in ingress section */
                SOC_IF_ERROR_RETURN
                    (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR, 
                                        SOC_STABLE_STALE, SOC_STABLE_FIELD, 0));
                /* Clean up generated state and restart as Level 1 */
                BCM_IF_ERROR_RETURN(_field_state_cleanup(unit, fc));
                rv = _field_fb2_stage_ingress_reinit(unit, fc, stage_fc);
            }
            if (BCM_SUCCESS(rv)) {
                stage_id = _BCM_FIELD_STAGE_EGRESS;
                BCM_IF_ERROR_RETURN
                    (_field_stage_control_get(unit, stage_id, &stage_fc));
                oldl2warm = fc->l2warm;
                rv = _field_fb2_stage_egress_reinit(unit, fc, stage_fc);
                if ((rv == BCM_E_INTERNAL) && (fc->scache_size > 0) && 
                    (fc->l2warm == 0) && (oldl2warm != 0)) {
                    /* Stale scache in egress section */
                    SOC_IF_ERROR_RETURN
                        (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR,
                                            SOC_STABLE_STALE, 
                                            SOC_STABLE_FIELD, 0));
                    /* Clean up generated state and restart as Level 1 */
                    BCM_IF_ERROR_RETURN(_field_state_cleanup(unit, fc));
                    stage_id = _BCM_FIELD_STAGE_INGRESS;
                    BCM_IF_ERROR_RETURN
                        (_field_stage_control_get(unit, stage_id, &stage_fc));
                    rv = _field_fb2_stage_ingress_reinit(unit, fc, stage_fc);
                    if (BCM_SUCCESS(rv)) {
                        stage_id = _BCM_FIELD_STAGE_EGRESS;
                        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, 
                                            stage_id, &stage_fc));
                        rv = _field_fb2_stage_egress_reinit(unit, fc, stage_fc);
                    }
                }
            }
            if (BCM_SUCCESS(rv)) {
                stage_id = _BCM_FIELD_STAGE_LOOKUP;
                BCM_IF_ERROR_RETURN
                    (_field_stage_control_get(unit, stage_id, &stage_fc));
                oldl2warm = fc->l2warm;
                rv = _field_fb2_stage_lookup_reinit(unit, fc, stage_fc);
                if ((rv == BCM_E_INTERNAL) && (fc->scache_size > 0) && 
                    (fc->l2warm == 0) && (oldl2warm != 0)) {
                    /* Stale scache in lookup section */
                    SOC_IF_ERROR_RETURN
                        (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR,
                                            SOC_STABLE_STALE, 
                                            SOC_STABLE_FIELD, 0));
                    /* Clean up generated state and restart as Level 1 */
                    BCM_IF_ERROR_RETURN(_field_state_cleanup(unit, fc));
                    stage_id = _BCM_FIELD_STAGE_INGRESS;
                    BCM_IF_ERROR_RETURN
                        (_field_stage_control_get(unit, stage_id, &stage_fc));
                    rv = _field_fb2_stage_ingress_reinit(unit, fc, stage_fc);
                    if (BCM_SUCCESS(rv)) {
                        stage_id = _BCM_FIELD_STAGE_EGRESS;
                        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, 
                                            stage_id, &stage_fc));
                        rv = _field_fb2_stage_egress_reinit(unit, fc, stage_fc);
                    }
                    if (BCM_SUCCESS(rv)) {
                        stage_id = _BCM_FIELD_STAGE_LOOKUP;
                        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, 
                                            stage_id, &stage_fc));
                        rv = _field_fb2_stage_lookup_reinit(unit, fc, stage_fc);
                    }
                }
            }
#endif
        } else if (SOC_IS_TRIUMPH(unit)
                   || SOC_IS_VALKYRIE(unit)                
                   || SOC_IS_ENDURO(unit)
                   || SOC_IS_TRIUMPH2(unit)
                   || SOC_IS_APOLLO(unit)
                   || SOC_IS_VALKYRIE2(unit)
                   || SOC_IS_SC_CQ(unit)
                   || SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)
                   ) {
#if defined(BCM_TRX_SUPPORT)
            uint8 oldl2warm = 0;
            stage_id = _BCM_FIELD_STAGE_INGRESS;
            BCM_IF_ERROR_RETURN
                (_field_stage_control_get(unit, stage_id, &stage_fc));
            rv = _field_tr2_stage_ingress_reinit(unit, fc, stage_fc);
            if ((rv == BCM_E_INTERNAL) && (fc->scache_size > 0) && 
                (fc->l2warm == 0)) {
                /* Stale scache in ingress section */
                SOC_IF_ERROR_RETURN
                    (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR, 
                                        SOC_STABLE_STALE, SOC_STABLE_FIELD, 0));
                /* Clean up generated state and restart as Level 1 */
                BCM_IF_ERROR_RETURN(_field_state_cleanup(unit, fc));
                rv = _field_tr2_stage_ingress_reinit(unit, fc, stage_fc);
            }
            if (BCM_SUCCESS(rv)) {
                stage_id = _BCM_FIELD_STAGE_EGRESS;
                BCM_IF_ERROR_RETURN
                    (_field_stage_control_get(unit, stage_id, &stage_fc));
                oldl2warm = fc->l2warm;
                rv = _field_tr2_stage_egress_reinit(unit, fc, stage_fc);
                if ((rv == BCM_E_INTERNAL) && (fc->scache_size > 0) && 
                    (fc->l2warm == 0) && (oldl2warm != 0)) {
                    /* Stale scache in egress section */
                    SOC_IF_ERROR_RETURN
                        (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR,
                                            SOC_STABLE_STALE, 
                                            SOC_STABLE_FIELD, 0));
                    /* Clean up generated state and restart as Level 1 */
                    BCM_IF_ERROR_RETURN(_field_state_cleanup(unit, fc));
                    stage_id = _BCM_FIELD_STAGE_INGRESS;
                    BCM_IF_ERROR_RETURN
                        (_field_stage_control_get(unit, stage_id, &stage_fc));
                    rv = _field_tr2_stage_ingress_reinit(unit, fc, stage_fc);
                    if (BCM_SUCCESS(rv)) {
                        stage_id = _BCM_FIELD_STAGE_EGRESS;
                        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, 
                                            stage_id, &stage_fc));
                        rv = _field_tr2_stage_egress_reinit(unit, fc, stage_fc);
                    }
                }
            }
            if (BCM_SUCCESS(rv)) {
                stage_id = _BCM_FIELD_STAGE_LOOKUP;
                BCM_IF_ERROR_RETURN
                    (_field_stage_control_get(unit, stage_id, &stage_fc));
                oldl2warm = fc->l2warm;
                rv = _field_tr2_stage_lookup_reinit(unit, fc, stage_fc);
                if ((rv == BCM_E_INTERNAL) && (fc->scache_size > 0) && 
                    (fc->l2warm == 0) && (oldl2warm != 0)) {
                    /* Stale scache in lookup section */
                    SOC_IF_ERROR_RETURN
                        (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR,
                                            SOC_STABLE_STALE, 
                                            SOC_STABLE_FIELD, 0));
                    /* Clean up generated state and restart as Level 1 */
                    BCM_IF_ERROR_RETURN(_field_state_cleanup(unit, fc));
                    stage_id = _BCM_FIELD_STAGE_INGRESS;
                    BCM_IF_ERROR_RETURN
                        (_field_stage_control_get(unit, stage_id, &stage_fc));
                    rv = _field_tr2_stage_ingress_reinit(unit, fc, stage_fc);
                    if (BCM_SUCCESS(rv)) {
                        stage_id = _BCM_FIELD_STAGE_EGRESS;
                        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, 
                                            stage_id, &stage_fc));
                        rv = _field_tr2_stage_egress_reinit(unit, fc, stage_fc);
                    }
                    if (BCM_SUCCESS(rv)) {
                        stage_id = _BCM_FIELD_STAGE_LOOKUP;
                        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, 
                                            stage_id, &stage_fc));
                        rv = _field_tr2_stage_lookup_reinit(unit, fc, stage_fc);
                    }
                }
            }
            if (BCM_SUCCESS(rv) && soc_feature(unit, soc_feature_esm_support)) {
                stage_id = _BCM_FIELD_STAGE_EXTERNAL;
                rv = _field_stage_control_get(unit, stage_id, &stage_fc);
                if (rv == BCM_E_UNAVAIL) {
                    /* External stage not configured => Skip it */

                    return (BCM_E_NONE);
                }
                BCM_IF_ERROR_RETURN(rv);

                oldl2warm = fc->l2warm;
                rv = _field_tr2_stage_external_reinit(unit, fc, stage_fc);
                if ((rv == BCM_E_INTERNAL) && (fc->scache_size > 0) && 
                    (fc->l2warm == 0) && (oldl2warm != 0)) {
                    /* Stale scache in lookup section */
                    SOC_IF_ERROR_RETURN
                        (soc_event_generate(unit, SOC_SWITCH_EVENT_STABLE_ERROR,
                                            SOC_STABLE_STALE, 
                                            SOC_STABLE_FIELD, 0));
                    /* Clean up generated state and restart as Level 1 */
                    BCM_IF_ERROR_RETURN(_field_state_cleanup(unit, fc));
                    stage_id = _BCM_FIELD_STAGE_INGRESS;
                    BCM_IF_ERROR_RETURN
                        (_field_stage_control_get(unit, stage_id, &stage_fc));
                    rv = _field_tr2_stage_ingress_reinit(unit, fc, stage_fc);
                    if (BCM_SUCCESS(rv)) {
                        stage_id = _BCM_FIELD_STAGE_EGRESS;
                        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, 
                                            stage_id, &stage_fc));
                        rv = _field_tr2_stage_egress_reinit(unit, fc, stage_fc);
                    }
                    if (BCM_SUCCESS(rv)) {
                        stage_id = _BCM_FIELD_STAGE_LOOKUP;
                        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, 
                                            stage_id, &stage_fc));
                        rv = _field_tr2_stage_lookup_reinit(unit, fc, stage_fc);
                    }
                    if (BCM_SUCCESS(rv)) {
                        stage_id = _BCM_FIELD_STAGE_EXTERNAL;
                        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, 
                                            stage_id, &stage_fc));
                        rv = _field_tr2_stage_external_reinit(unit, fc, stage_fc);
                    }
                }
            }
#endif /* BCM_TRX_SUPPORT */
        }

        if (BCM_FAILURE(rv)) {
            _field_stage_delete(unit, fc, stage_fc);
            return (rv);  
        }
    } 
#endif
    _field_control[unit]->init = TRUE;
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_group_traverse
 * Purpose:
 *      Traverse all the fp groups in the system, calling a specified
 *      callback for each one
 * Parameters:
 *      unit - (IN) Unit number.
 *      callback - (IN) A pointer to the callback function to call for each fp group
 *      user_data - (IN) Pointer to user data to supply in the callback
 * Returns:
 *      BCM_E_xxx
 * Notes:
 */
int 
bcm_esw_field_group_traverse(int unit, bcm_field_group_traverse_cb callback,
                             void *user_data)
{
    bcm_field_group_t *grp_arr;/* Field group pointers.    */ 
    _field_control_t *fc;      /* Field control structure. */
    _field_group_t *fg;        /* Field group structure.   */
    int group_count;           /* Number of fp groups.     */
    int mem_sz;                /* Allocated memory size.   */
    int idx;                   /* Group array iterator.    */
    int rv = BCM_E_NONE;       /* Operation return status. */

    /* Input parameters check. */
    if (NULL == callback) {
        return (BCM_E_PARAM);
    }

    /* Field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc)); 
    FP_LOCK(fc);

    /* Count fp groups. */
    fg = fc->groups;
    group_count = 0;
    while (fg != NULL) {
        group_count++;
        fg = fg->next;
    }

    if (0 == group_count) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* 
     * API can not use field contol groups linked list, 
     * since group might be destroyed in callback.  
     */
    mem_sz = group_count * sizeof(bcm_field_group_t);
    grp_arr = NULL;
    _FP_XGS3_ALLOC(grp_arr, mem_sz, "FP groups array");
    if (NULL == grp_arr) {
        FP_UNLOCK(fc);
        return (BCM_E_MEMORY);
    }

    /* Programm fp group ids into allocated array. */
    fg = fc->groups;
    idx = 0;
    while (fg != NULL) {
        grp_arr[idx] = fg->gid;
        idx++;
        fg = fg->next;
    }

    /* Call user callback. */
    for (idx = 0; idx < group_count; idx++) {
        rv = (*callback)(unit, grp_arr[idx], user_data);
        if (BCM_FAILURE(rv)) {
            break;
        }
    }
    FP_UNLOCK(fc);
    sal_free(grp_arr);
    return (rv);
}

/*
 * Function: bcm_esw_field_detach
 *
 * Purpose:
 *     Free resources associated with field module
 *
 * Parameters:
 *     unit - BCM device number
 *
 * Returns:
 *     BCM_E_INIT - BCM Unit not initialized.
 *     BCM_E_XXX  - Error code from bcm_field_group_destroy() or
 *                  bcm_field_entry_destroy_all().
 *     BCM_E_NONE - Success
 */

int
bcm_esw_field_detach(int unit)
{
    _field_control_t    *fc;
    _field_group_t      *fg;
    int                  rv;

    FP_VVERB(("FP(unit %d) vverb: bcm_field_detach()\n", unit));

    fc = _field_control[unit];

    if (NULL == fc) {
        return (BCM_E_NONE);
    }

    soc_counter_extra_unregister(unit, _bcm_esw_fp_counters_collect);
    /* Unregister counter collection callback. */
    if (fc->fc_lock != NULL) {
        FP_LOCK(fc);
    }

    /* Destroy all entries in unit. */
    rv = bcm_esw_field_entry_destroy_all(unit);
    if (BCM_FAILURE(rv)) {
        if (fc->fc_lock != NULL) {
            FP_UNLOCK(fc);
        }
        return (rv);
    }

    /* Destroy all statistics entities. */
    rv = _field_stat_destroy_all(unit);
    if (BCM_FAILURE(rv)) {
        if (fc->fc_lock != NULL) {
            FP_UNLOCK(fc);
        }
        return (rv);
    }

    /* Destroy all policers. */
    rv = bcm_esw_policer_destroy_all(unit);
    if (BCM_FAILURE(rv)) {
        if (fc->fc_lock != NULL) {
            FP_UNLOCK(fc);
        }
        return (rv);
    }

    /* Destroy all groups in unit. */
    fg = fc->groups;
    while (fg != NULL) {
        
        rv = bcm_esw_field_group_destroy(unit, fg->gid);
        if (BCM_FAILURE(rv)) {
            if (fc->fc_lock != NULL) {
                FP_UNLOCK(fc);
            }
            return (rv);
        }
        fg = fc->groups;
    }

    /* Device specific detach */
    if (NULL != fc->functions.fp_detach) {
    rv = fc->functions.fp_detach(unit, fc);
    if (BCM_FAILURE(rv)) {
        if (fc->fc_lock != NULL) {
            FP_UNLOCK(fc);  
        }
        return (rv);
    }
    }

    /* Destroy a Unit's stages*/
    rv = _field_stages_destroy(unit, fc);
    if (BCM_FAILURE(rv)) {
        if (fc->fc_lock != NULL) {
            FP_UNLOCK(fc);  
        }
        return (rv);
    }
    FP_UNLOCK(fc);  

    _field_control_free(unit, fc);
    return (BCM_E_NONE);
}

/*
 * Function: bcm_esw_field_status_get
 *  
 * Purpose:
 *     DEPRECATED
 *
 * Parameters:
 *     unit   - BCM device number
 *     status - (OUT) Status for field module
 *
 * Returns:
 *     BCM_E_XXX 
 */
int
bcm_esw_field_status_get(int unit, bcm_field_status_t *status)
{
    return (BCM_E_UNAVAIL);
}

/*
 * Function: bcm_esw_field_control_get
 *
 * Purpose:
 *     Get control status info.
 *
 * Parameters:
 *     unit     - (IN)  BCM device number.
 *     control  - (IN)  Control element to get.
 *     status   - (OUT) Status of field element.
 *
 * Returns:
 *     BCM_E_INIT    - BCM unit not initialized
 *     BCM_E_PARAM   - *state pointing to NULL
 *     BCM_E_NONE    - Success
 */
int
bcm_esw_field_control_get(int unit, bcm_field_control_t control, uint32 *state)
{
    _field_control_t    *fc;             /* Field control structure.      */
    int                 rv = BCM_E_NONE; /* Operation return status.      */
    uint32              val1;
    uint32              val2;
    uint32              reg_val;         /* Register value buffer.        */
#if defined (BCM_TRX_SUPPORT)
    uint64              val64;           /* Register 64bitvalue buffer.   */
#endif /* BCM_TRX_SUPPORT */

    if (state == NULL) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    switch (control) {
      case bcmFieldControlIntraDoubleEnable:
          *state = (fc->flags & _FP_INTRASLICE_ENABLE) ? TRUE : FALSE;
          break;
      case bcmFieldControlColorIndependent:
          *state = (fc->flags & _FP_COLOR_INDEPENDENT) ? TRUE : FALSE;
          break;
      case bcmFieldControlStage:
          *state = fc->stage;
          break;
#ifdef BCM_EASYRIDER_SUPPORT
      case bcmFieldControlUdfHigig0:
          if (SOC_REG_IS_VALID(unit, UDF_CONFIGr)) {
              rv = READ_UDF_CONFIGr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, UDF_CONFIGr, reg_val,
                                             CMIC_HIG_HDR_UDF22_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlUdfHigig1:
          if (SOC_REG_IS_VALID(unit, UDF_CONFIGr)) { 
              rv = READ_UDF_CONFIGr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, UDF_CONFIGr, reg_val,
                                             CMIC_HIG_HDR_UDF21_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlUdfHigig2:
          if (SOC_REG_IS_VALID(unit, UDF_CONFIGr)) { 
              rv = READ_UDF_CONFIGr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, UDF_CONFIGr, reg_val,
                                             CMIC_HIG_HDR_UDF20_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
#endif /* BCM_EASYRIDER_SUPPORT */

#if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT)
      case bcmFieldControlExternalUdfEnable:
          if (SOC_REG_IS_VALID(unit, ESM_KEYGEN_CTLr)) {
              rv = READ_ESM_KEYGEN_CTLr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, ESM_KEYGEN_CTLr, reg_val,
                                             L2_ACL_PAYLOAD_MODEf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
#endif /* !(BCM_TRIUMPH2_SUPPORT || BCM_TRIUMPH_SUPPORT) */

      case bcmFieldControlSharedVlanFieldSet:
          if (SOC_IS_TRX(unit)) {
              rv = (BCM_E_UNAVAIL);
              break;
          }
          if (SOC_REG_FIELD_VALID(unit, ING_CONFIGr, MAP_FID_ID_TO_INNER_TAGf)) {
              rv = READ_ING_CONFIGr(unit, &reg_val);
              val1 = soc_reg_field_get(unit, ING_CONFIGr, reg_val, MAP_FID_ID_TO_INNER_TAGf);
              val2 = soc_reg_field_get(unit, ING_CONFIGr, reg_val, MAP_FID_ID_TO_OUTER_TAGf);
              if ((0 == val1) && (0 == val2)) {
                  *state = BCM_FIELD_SHARED_VLAN_NONE;
              }
              if ((0 == val1) && (1 == val2)) {
                  *state = BCM_FIELD_SHARED_VLAN_OUTER;
              }
              if ((1 == val1) && (0 == val2)) {
                  *state = BCM_FIELD_SHARED_VLAN_INNER;
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
#if defined(BCM_TRX_SUPPORT)
      case bcmFieldControlArpAsIp:
          if (SOC_REG_FIELD_VALID(unit, ING_CONFIG_64r, ARP_RARP_TO_FPf)) {
              rv = READ_ING_CONFIG_64r(unit, &val64);
              if (BCM_SUCCESS(rv)) {
                  reg_val = soc_reg64_field32_get(unit, ING_CONFIG_64r, 
                                                  val64, ARP_RARP_TO_FPf);
                  *state = (0x1 & reg_val) ? TRUE : FALSE;
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlRarpAsIp:
          if (SOC_REG_FIELD_VALID(unit, ING_CONFIG_64r, ARP_RARP_TO_FPf)) { 
              rv = READ_ING_CONFIG_64r(unit, &val64);
              if (BCM_SUCCESS(rv)) {
                  reg_val = soc_reg64_field32_get(unit, ING_CONFIG_64r, 
                                                  val64, ARP_RARP_TO_FPf);
                  *state = (0x2 & reg_val) ? TRUE : FALSE;
              } 
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlRedirectIngressVlanCheck:
          if (SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) { 
              rv = READ_SW2_FP_DST_ACTION_CONTROLr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, SW2_FP_DST_ACTION_CONTROLr,
                                             reg_val, VLAN_CHECK_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlRedirectNonUcastTrunkResolve:
          if (SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) { 
              rv = READ_SW2_FP_DST_ACTION_CONTROLr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, SW2_FP_DST_ACTION_CONTROLr,
                                             reg_val, LAG_RES_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlRedirectNonUcastEtherTrunkResolve:
          if (SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) { 
              rv = READ_SW2_FP_DST_ACTION_CONTROLr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, SW2_FP_DST_ACTION_CONTROLr,
                                             reg_val, LAG_RES_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlRedirectNonUcastFabricTrunkResolve:
          if (SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) { 
              rv = READ_SW2_FP_DST_ACTION_CONTROLr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, SW2_FP_DST_ACTION_CONTROLr,
                                             reg_val, HGTRUNK_RES_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlRedirectExcludeSrcPort:
          if (SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) { 
              rv = READ_SW2_FP_DST_ACTION_CONTROLr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, SW2_FP_DST_ACTION_CONTROLr,
                                             reg_val, SRC_REMOVAL_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlRedirectPortFloodBlock:
          if (SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) { 
              rv = READ_SW2_FP_DST_ACTION_CONTROLr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, SW2_FP_DST_ACTION_CONTROLr,
                                             reg_val, PORT_BLOCK_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case  bcmFieldControlRedirectVlanFloodBlock: 
          if (SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) { 
              rv = READ_SW2_FP_DST_ACTION_CONTROLr(unit, &reg_val);
              if (BCM_SUCCESS(rv)) {
                  *state = soc_reg_field_get(unit, SW2_FP_DST_ACTION_CONTROLr,
                                             reg_val, VLAN_BLOCK_ENf);
              }
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
#endif /* BCM_TRX_SUPPORT */
      default:
          rv = (BCM_E_UNAVAIL);
    }
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_control_set
 *
 * Purpose:
 *     Set control status.
 *
 * Parameters:
 *     unit     - (IN) BCM device number.
 *     control  - (IN) Control element to set.
 *     state    - (IN) State (0/1).
 *
 * Returns:
 *     BCM_E_NONE    - Success
 *     BCM_E_INIT    - BCM unit not initialized
 *     BCM_E_PARAM   - Flag state not valid on device
 */
int
bcm_esw_field_control_set(int unit, bcm_field_control_t control, uint32 state)
{
    _field_control_t    *fc;              /* Field control structure.   */
    int                 rv = BCM_E_NONE;  /* Operation return status.   */
    uint32              reg_values[2];    /* Register value buffer.     */
    soc_field_t         reg_fields[2];    /* Register fields to modify. */
    int                 field_count = 2;  /* Number of updated fields.  */
    reg_values[0] = reg_values[1] = (state == TRUE) ? 1: 0;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    switch (control) {
      case bcmFieldControlIntraDoubleEnable:
          if (soc_feature(unit, soc_feature_field_intraslice_double_wide)) {
              if (state == 0) {
                  fc->flags &= ~_FP_INTRASLICE_ENABLE;
              } else {
                  fc->flags |= _FP_INTRASLICE_ENABLE;
              }
          } else if (state == 0) {
              fc->flags &= ~_FP_INTRASLICE_ENABLE;
          } else {
              FP_ERR(("FP(unit %d) Error: Device doesn't support intraslice\n", unit));
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlColorIndependent:
          if (soc_feature(unit, soc_feature_field_color_indep)) {
              if (state == 0) {
                  fc->flags &= ~_FP_COLOR_INDEPENDENT;
              } else {
                  fc->flags |= _FP_COLOR_INDEPENDENT;
              }
#ifdef BCM_EASYRIDER_SUPPORT
              if (SOC_IS_EASYRIDER(unit)) {
                  rv =  soc_reg_field32_modify(unit, CSE_CONFIGr, REG_PORT_ANY,
                                               GREEN_TO_PIDf, state ? 1 : 0);
              }
#endif /* BCM_EASYRIDER_SUPPORT */
          } else if (state == 0) {
              fc->flags &= ~_FP_COLOR_INDEPENDENT;
          } else {
              FP_ERR(("FP(unit %d) Error: Color Independence unsupported on this unit\n", unit));
              rv = BCM_E_UNAVAIL;
          }
          break;
      case bcmFieldControlStage:
          if (state >= bcmFieldStageCount) {
              FP_ERR(("FP(unit %d) Error: Unknown stage=%d\n", unit, state));
              rv = (BCM_E_PARAM);
          } else if ((state == bcmFieldStageIngressLate) &&
                     (0 == soc_feature(unit, soc_feature_field_ingress_late))) {
              FP_ERR(("FP(unit %d) Error: No IngressLate stage.\n", unit));
              rv = (BCM_E_UNAVAIL);
          } else {
              fc->stage = state;
          }
          break;
#ifdef BCM_EASYRIDER_SUPPORT
      case bcmFieldControlUdfHigig0:
          if (SOC_REG_IS_VALID(unit, UDF_CONFIGr)) { 
              reg_fields[0] = CMIC_HIG_HDR_UDF22_ENf;
              reg_fields[1] = P12_HIG_HDR_UDF22_ENf;

              /*  Update UDF_CONFIGr register. */
              rv = soc_reg_fields32_modify(unit, UDF_CONFIGr, REG_PORT_ANY,
                                           field_count, reg_fields, reg_values);
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlUdfHigig1:
          if (SOC_REG_IS_VALID(unit, UDF_CONFIGr)) {
              reg_fields[0] = CMIC_HIG_HDR_UDF21_ENf;
              reg_fields[1] = P12_HIG_HDR_UDF21_ENf;

              /*  Update UDF_CONFIGr register. */
              rv = soc_reg_fields32_modify(unit, UDF_CONFIGr, REG_PORT_ANY,
                                           field_count, reg_fields, reg_values);
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlUdfHigig2:
          if (SOC_REG_IS_VALID(unit, UDF_CONFIGr)) { 
              reg_fields[0] = CMIC_HIG_HDR_UDF20_ENf;
              reg_fields[1] = P12_HIG_HDR_UDF20_ENf;

              /*  Update UDF_CONFIGr register. */
              rv = soc_reg_fields32_modify(unit, UDF_CONFIGr, REG_PORT_ANY,
                                           field_count, reg_fields, reg_values);
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
#endif /* BCM_EASYRIDER_SUPPORT */
      case bcmFieldControlSharedVlanFieldSet:
          if (SOC_IS_TRX(unit)) {
              rv = (BCM_E_UNAVAIL);
              break;
          }
          if (SOC_REG_FIELD_VALID(unit, ING_CONFIGr, MAP_FID_ID_TO_INNER_TAGf)) {
              reg_fields[0] = MAP_FID_ID_TO_INNER_TAGf;
              reg_fields[1] = MAP_FID_ID_TO_OUTER_TAGf;
              if (BCM_FIELD_SHARED_VLAN_NONE == state) {
                  reg_values[0] = 0;
                  reg_values[1] = 0;
              } else if (BCM_FIELD_SHARED_VLAN_INNER == state) {
                  reg_values[0] = 1;
                  reg_values[1] = 0;
              } else if (BCM_FIELD_SHARED_VLAN_OUTER == state) {
                  reg_values[0] = 0;
                  reg_values[1] = 1;
              } else {
                  rv = (BCM_E_PARAM);
                  break;
              }
              rv =  soc_reg_fields32_modify(unit, ING_CONFIGr, REG_PORT_ANY,
                                            field_count, reg_fields, reg_values);
          } else {
              rv = (BCM_E_UNAVAIL); 
          }
          break;
#if defined(BCM_TRX_SUPPORT)
      case bcmFieldControlArpAsIp:
      case bcmFieldControlRarpAsIp:
          if (SOC_REG_FIELD_VALID(unit, ING_CONFIG_64r, ARP_RARP_TO_FPf)) {
              rv = _bcm_field_trx_control_arp_set(unit, control, state);
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
      case bcmFieldControlRedirectIngressVlanCheck:
          if (!SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) {
              rv = (BCM_E_UNAVAIL);
          } else {
              reg_fields[0] = VLAN_CHECK_ENf;
              field_count = 1;
              rv = soc_reg_fields32_modify(unit, SW2_FP_DST_ACTION_CONTROLr,
                                          REG_PORT_ANY, field_count,
                                          reg_fields, reg_values);
          }
          break;
      case bcmFieldControlRedirectNonUcastTrunkResolve:
          if (!SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) {
              rv = (BCM_E_UNAVAIL);
          } else {
              reg_fields[0] = LAG_RES_ENf;
              reg_fields[1] = HGTRUNK_RES_ENf;
              field_count = 2;
              rv = soc_reg_fields32_modify(unit, SW2_FP_DST_ACTION_CONTROLr, 
                                           REG_PORT_ANY, field_count, 
                                           reg_fields, reg_values);
          }
          break;
      case bcmFieldControlRedirectNonUcastEtherTrunkResolve:
          if (!SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) {
              rv = (BCM_E_UNAVAIL);
          } else {
              reg_fields[0] = LAG_RES_ENf;
              field_count = 1;
              rv = soc_reg_fields32_modify(unit, SW2_FP_DST_ACTION_CONTROLr, 
                                           REG_PORT_ANY, field_count, 
                                           reg_fields, reg_values);
          }
          break;
      case bcmFieldControlRedirectNonUcastFabricTrunkResolve:
          if (!SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) {
              rv = (BCM_E_UNAVAIL);
          } else {
              reg_fields[0] = HGTRUNK_RES_ENf;
              field_count = 1;
              rv = soc_reg_fields32_modify(unit, SW2_FP_DST_ACTION_CONTROLr, 
                                           REG_PORT_ANY, field_count, 
                                           reg_fields, reg_values);
          }
          break;
      case bcmFieldControlRedirectExcludeSrcPort:
          if (!SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) {
              rv = (BCM_E_UNAVAIL);
          } else {
              reg_fields[0] = HG_SRC_REMOVAL_ENf;
              reg_fields[1] = SRC_REMOVAL_ENf;
              field_count = 2;
              rv = soc_reg_fields32_modify(unit, SW2_FP_DST_ACTION_CONTROLr, 
                                           REG_PORT_ANY, field_count, 
                                           reg_fields, reg_values);
          }
          break;
      case bcmFieldControlRedirectPortFloodBlock:
          if (!SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) {
              rv = (BCM_E_UNAVAIL);
          } else {
              reg_fields[0] = PORT_BLOCK_ENf;
              field_count = 1;
              rv = soc_reg_fields32_modify(unit, SW2_FP_DST_ACTION_CONTROLr, 
                                           REG_PORT_ANY, field_count, 
                                           reg_fields, reg_values);
          }
          break;
      case  bcmFieldControlRedirectVlanFloodBlock: 
          if (!SOC_REG_IS_VALID(unit, SW2_FP_DST_ACTION_CONTROLr)) {
              rv = (BCM_E_UNAVAIL);
          } else {
              reg_fields[0] = VLAN_BLOCK_ENf;
              field_count = 1;
              rv = soc_reg_fields32_modify(unit, SW2_FP_DST_ACTION_CONTROLr, 
                                           REG_PORT_ANY, field_count, 
                                           reg_fields, reg_values);
          }
          break;
#endif /* BCM_TRX_SUPPORT */
#if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT)
      case bcmFieldControlExternalUdfEnable:
          if (SOC_REG_IS_VALID(unit, ESM_KEYGEN_CTLr)) {
              rv = soc_reg_field32_modify(unit, ESM_KEYGEN_CTLr, REG_PORT_ANY, 
                                          L2_ACL_PAYLOAD_MODEf, state);
          } else {
              rv = (BCM_E_UNAVAIL);
          }
          break;
#endif /* !(BCM_TRIUMPH2_SUPPORT || BCM_TRIUMPH_SUPPORT) */


      default:
          rv = (BCM_E_UNAVAIL);
    }
    FP_UNLOCK(fc);
    return (rv);
}


/* Section: Group Management */

/*
 * Function: bcm_esw_field_group_create
 *
 * Purpose:
 *     Create a field group based on the field group selector flags.
 *
 * Parameters:
 *     unit - BCM device number.
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *     group - (OUT) New field group ID
 *
 * Returns:
 *     BCM_E_INIT     - BCM unit not initialized
 *     BCM_E_PARAM    - pri out of range (0-15 for FB & ER) or group == NULL
 *     BCM_E_RESOURCE - no select codes will satisfy qualifier set
 *     BCM_E_NONE     - Success
 *
 * Notes:
 *      Allocates a hardware slice at the requested priority or better.
 *      Higher numerical value for priority has better priority for
 *      conflict resolution when there is a search hit on multiple slices.
 */
int
bcm_esw_field_group_create(int unit,
                           bcm_field_qset_t qset,
                           int pri,
                           bcm_field_group_t *group)
{
    _field_control_t   *fc;     /* Field control structure. */
    int                rv;      /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* qset and pri are validated in bcm_field_group_create_mode_id(). */
    rv = _field_group_id_generate(unit, group);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = bcm_esw_field_group_create_mode_id(unit, qset, pri,
                                            bcmFieldGroupModeDefault, *group);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_create_id
 *     
 * Purpose:
 *     Create a field group based on the field group selector flags
 *     with a requested ID
 *
 * Parameters:
 *     unit - BCM device number.
 *     port - Port number
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    group - Requested field group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - No unused group/slices left
 *     BCM_E_PARAM     - priority out of range (0-15 for FB & ER)
 *     BCM_E_EXISTS    - group with that id already exists on this unit.
 *     BCM_E_MEMORY    - Group memory allocation failure
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_group_create_id(int unit,
                              bcm_field_qset_t qset,
                              int pri,
                              bcm_field_group_t group)
{
    _field_control_t   *fc;     /* Field control structure. */
    int                rv;      /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Qset, pri and mode are validated in bcm_field_group_create_mode_id(). */
    rv = bcm_esw_field_group_create_mode_id(unit, qset, pri,
                                            bcmFieldGroupModeDefault, group);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_create_mode
 *     
 * Purpose:
 *
 * Parameters:
 *     unit - BCM device number.
 *     port - Port number
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - (OUT) New field group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - No select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_create_mode(int unit,
                                bcm_field_qset_t qset,
                                int pri,
                                bcm_field_group_mode_t mode,
                                bcm_field_group_t *group)
{
    _field_control_t   *fc;     /* Field control structure. */
    int                rv;      /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Qset, pri and mode are validated in bcm_field_group_create_mode_id(). */
    rv = _field_group_id_generate(unit, group);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }
    rv = bcm_esw_field_group_create_mode_id(unit, qset, pri, mode, *group);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_create_mode_id
 *     
 * Purpose:
 *     Create a group with both a mode (single, double, etc.) and a Group ID.
 *
 * Parameters:
 *     unit - BCM device number.
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - Requested field group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_create_mode_id(int unit,
                                   bcm_field_qset_t qset,
                                   int pri,
                                   bcm_field_group_mode_t mode,
                                   bcm_field_group_t group)
{
    bcm_port_config_t  port_config;/* Device port config structure.*/
    _field_control_t   *fc;        /* Field control structure.     */
    bcm_pbmp_t         pbmp;       /* Group port bitmap.           */
    int                rv;         /* Operation return status.     */

    /* Read device port configuration. */ 
    BCM_IF_ERROR_RETURN(bcm_esw_port_config_get(unit, &port_config));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    BCM_PBMP_ASSIGN(pbmp, port_config.all);

    rv =  bcm_esw_field_group_ports_create_mode_id(unit, pbmp, qset, 
                                                   pri, mode, group);
    
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_port_create_mode
 *     
 * Purpose:
 *     Create a group with both a mode (single, double, etc.) and a single
 *     port.
 *
 * Parameters:
 *     unit - BCM device number.
 *     port - Port number where group is defined
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - (OUT) field Group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_port_create_mode(int unit, bcm_port_t port,
                                     bcm_field_qset_t qset, int pri,
                                     bcm_field_group_mode_t mode,
                                     bcm_field_group_t *group)
{
    _field_control_t   *fc;     /* Field control structure. */
    int                rv;      /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* qset and pri are validated in bcm_field_group_port_create_mode_id(). */
    rv = _field_group_id_generate(unit, group);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = bcm_esw_field_group_port_create_mode_id(unit, port, qset, 
                                                 pri, mode, *group);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_port_create_mode_id
 *     
 * Purpose:
 *     Create a group with a mode (single, double, etc.), a single port,
 *     and a Group ID.
 *
 * Parameters:
 *     unit - BCM device number.
 *     port - Port number where group is defined
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - Requested field group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_port_create_mode_id(int unit, bcm_port_t port,
                                        bcm_field_qset_t qset, int pri,
                                        bcm_field_group_mode_t mode,
                                        bcm_field_group_t group)
{
    _field_control_t   *fc;     /* Field control structure. */
    bcm_pbmp_t         pbmp;    /* Group port bitmap.       */
    int                rv;      /* Operation return status. */
    bcm_port_t         local_port; /* Local port to handle gport as input */


    BCM_PBMP_CLEAR(pbmp);
    if (BCM_GPORT_IS_SET(port)) {
        BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &local_port));
    } else {
        local_port = port;
    }
    BCM_PBMP_PORT_SET(pbmp, local_port);

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = bcm_esw_field_group_ports_create_mode_id(unit, pbmp, qset, 
                                                  pri, mode, group);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_ports_create_mode
 *     
 * Purpose:
 *     Create a group with both a mode (single, double, etc.) and a port bitmap.
 *
 * Parameters:
 *     unit - BCM device number.
 *     pbmp - Ports where group is defined
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - (OUT) field Group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_ports_create_mode(int unit, bcm_pbmp_t pbmp,
                                      bcm_field_qset_t qset, int pri,
                                      bcm_field_group_mode_t mode,
                                      bcm_field_group_t *group)
{
    _field_control_t   *fc;     /* Field control structure. */
    int                rv;      /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* qset and pri are validated in bcm_field_group_ports_create_mode_id(). */
    rv = _field_group_id_generate(unit, group);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = bcm_esw_field_group_ports_create_mode_id(unit, pbmp, qset, 
                                                  pri, mode, *group);
    FP_UNLOCK(fc);
    return (rv);
}

/* Function: bcm_esw_field_group_wlan_create_mode
 *     
 * Purpose:
 *     Create a wlan field group with a mode (single, double, etc.).
 *
 * Parameters:
 *     unit - BCM device number.
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - (OUT) field Group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_wlan_create_mode(int unit, bcm_field_qset_t qset, int pri,
                                     bcm_field_group_mode_t mode,
                                     bcm_field_group_t *group)
{
    _field_control_t   *fc;     /* Field control structure. */
    int                rv;      /* Operation return status. */


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* qset and pri are validated in bcm_field_group_ports_create_mode_id(). */
    rv = _field_group_id_generate(unit, group);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = bcm_esw_field_group_wlan_create_mode_id(unit, qset, pri, mode, *group);
    FP_UNLOCK(fc);
    return (rv);
}

/* Function: bcm_esw_field_group_wlan_create_mode_id
 *     
 * Purpose:
 *     Create a wlan field group with a mode (single, double, etc.).
 *
 * Parameters:
 *     unit - BCM device number.
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - (OUT) field Group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_wlan_create_mode_id(int unit, bcm_field_qset_t qset, int pri,
                                        bcm_field_group_mode_t mode,
                                        bcm_field_group_t group)
{
    bcm_port_config_t  port_config; /* Device port config structure. */
    _field_group_add_fsm_t fsm;     /* Group creation state machine. */
    _field_control_t       *fc;     /* Field control structure.      */
    int                    rv;      /* Operation return status.      */

    /* Read device port configuration. */ 
    BCM_IF_ERROR_RETURN(bcm_esw_port_config_get(unit, &port_config));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Initialize group creation tracking structure. */
    sal_memset(&fsm, 0, sizeof(_field_group_add_fsm_t));
    fsm.fsm_state = _BCM_FP_GROUP_ADD_STATE_START;
    fsm.priority  = pri;
    fsm.group_id  = group;
    BCM_PBMP_ASSIGN(fsm.pbmp, port_config.all);
    fsm.qset      = qset;
    fsm.mode      = mode;
    fsm.flags     = _BCM_FP_GROUP_ADD_WLAN;

    /*  Add FP group. */
    rv = _field_group_add(unit, &fsm);

    FP_UNLOCK(fc);
    return (rv);
}

/* Function: bcm_esw_field_group_config_create
 *
 * Purpose:
 *     Create a group with a mode (single, double, etc.), a port bitmap,
 *     group size and a Group ID. 
 * Parameters:
 *     unit - BCM device number.
 *     group_config - Group create attributes namely:
 *          flags       - (IN) Bits indicate which parameters have been
 *                             passed to API and should be used during group
 *                             creation.
 *          qset        - (IN) Field qualifier set
 *          priority    - (IN) Priority within allowable range,
 *                             or BCM_FIELD_GROUP_PRIO_ANY to automatically
 *                             assign a priority; each priority value may be
 *                             used only once
 *          mode        - (IN) Group mode (single, double, triple or Auto-wide)
 *          ports       - (IN) Ports where group is defined
 *          group       - (IN/OUT) Requested Group ID. If Group ID is not set,
 *                              then API allocates and returns the created
 *                              Group ID.
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_config_create(int unit,
                                  bcm_field_group_config_t *group_config)
{
    bcm_port_config_t  port_config; /* Device port config structure. */
    _field_group_add_fsm_t fsm;     /* Group creation state machine. */
    _field_control_t       *fc;     /* Field control structure.      */
    int                    rv;      /* Operation return status.      */

    if (NULL == group_config) {
        return (BCM_E_PARAM);
    }

    /* Check if passed group configuration is valid for this device */
    if ((0 == soc_feature(unit, soc_feature_field_ingress_two_slice_types))
        && ((group_config->flags & BCM_FIELD_GROUP_CREATE_SMALL)
            || (group_config->flags & BCM_FIELD_GROUP_CREATE_LARGE))) {
        return (BCM_E_UNAVAIL);
    }

    /* Read device port configuration. */ 
    BCM_IF_ERROR_RETURN(bcm_esw_port_config_get(unit, &port_config));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);
 
    if (!(group_config->flags & BCM_FIELD_GROUP_CREATE_WITH_ID)) {
        /* qset and pri are validated in bcm_field_group_create_mode_id(). */
        rv = _field_group_id_generate(unit, &group_config->group);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
    }

    /* Initialize group creation tracking structure. */
    sal_memset(&fsm, 0, sizeof(_field_group_add_fsm_t));
    fsm.fsm_state = _BCM_FP_GROUP_ADD_STATE_START;
    fsm.priority  = group_config->priority;
    fsm.group_id  = group_config->group;
    fsm.qset = group_config->qset;

    /* Apply group member port configuration */
    if (group_config->flags & BCM_FIELD_GROUP_CREATE_WITH_PORT) {
        BCM_PBMP_ASSIGN(fsm.pbmp, group_config->ports);
    } else {
        BCM_PBMP_ASSIGN(fsm.pbmp, port_config.all);
    }

    /* Apply group mode configuration */
    if (group_config->flags & BCM_FIELD_GROUP_CREATE_WITH_MODE) {
        fsm.mode = group_config->mode;
    } else {
        fsm.mode = bcmFieldGroupModeDefault;
    }

    /* Apply slice selection configuration */
    if (group_config->flags & BCM_FIELD_GROUP_CREATE_SMALL) {
        fsm.flags |= _BCM_FP_GROUP_ADD_SMALL_SLICE;
    } else if (group_config->flags & BCM_FIELD_GROUP_CREATE_LARGE) {
        fsm.flags |= _BCM_FP_GROUP_ADD_LARGE_SLICE;
    }

    /*  Add FP group. */
    rv = _field_group_add(unit, &fsm);

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_groups_ports_create_mode_id
 *     
 * Purpose:
 *     Create a group with a mode (single, double, etc.), a port bitmap, and
 *     a Group ID. In practice, the other group creation APIs call this one.
 *     This confirms that the required slice resources are available and
 *     calculates the sets of select codes needed to satisfy the Qset. It also
 *     creates the necessary internal data structures to manage the group.
 *
 * Parameters:
 *     unit - BCM device number.
 *     pbmp - Ports where group is defined
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - Requested Group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_ports_create_mode_id(int unit, bcm_pbmp_t pbmp,
                                         bcm_field_qset_t qset, int pri,
                                         bcm_field_group_mode_t mode,
                                         bcm_field_group_t group)
{
    _field_group_add_fsm_t fsm;     /* Group creation state machine. */
    _field_control_t       *fc;     /* Field control structure.      */
    int                    rv;      /* Operation return status.      */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Initialize group creation tracking structure. */
    sal_memset(&fsm, 0, sizeof(_field_group_add_fsm_t));
    fsm.fsm_state = _BCM_FP_GROUP_ADD_STATE_START;
    fsm.priority  = pri;
    fsm.group_id  = group;
    fsm.pbmp      = pbmp;
    fsm.qset      = qset;
    fsm.mode      = mode;

    /*  Add FP group. */
    rv = _field_group_add(unit, &fsm);

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_mode_get
 *
 * Purpose:
 *     Return the mode of a Group ID. This is its single, double or triple-wide
 *     state. Mode specified the number of slices allocated to the group.
 *
 * Parameters:
 *     unit  - (IN) BCM device number.
 *     group - (IN) Field group ID.
 *     mode  - (OUT) single, double, triple or auto mode.
 *     
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Group ID not found for in this unit
 *     BCM_E_PARAM     - mode pointing to NULL
 *     BCM_E_NONE      - Success
 *     
 */
int
bcm_esw_field_group_mode_get(int unit,
                             bcm_field_group_t group,
                             bcm_field_group_mode_t *mode)
{
    _field_control_t  *fc;     /* Field control structure.*/
    _field_group_t    *fg;     /* Field group info.       */
    int                rv;     /* Operation return value. */             

    if (mode == NULL) {
        FP_ERR(("FP(unit %d) Error: mode=>NULL\n", unit));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_ERR(("FP(unit %d) Error: group=%d not found \n", unit, group));
        FP_UNLOCK(fc);
        return (BCM_E_NOT_FOUND);
    }
    rv = _bcm_esw_field_group_mode_get(fg->flags, mode);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_set
 *    
 * Purpose:
 *     Update a previously created field group based on the field
 *     group selector flags
 *     
 * Parameters:
 *     unit  - BCM device number
 *     group - Field group ID
 *     qset  - Field qualifier set
 *     
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Group ID not found for in this unit
 *     BCM_E_RESOURCE  - No select code can satisfy qualifier set
 *     BCM_E_NONE      - Success
 *     
 * Notes:
 *     If no entry exist that use this group then updates are always
 *     permitted.
 *     If entries exist that use this group then updates are permitted
 *     only if it can be satisfied with the current selection of
 *     (fpf0, fpf1, fpf2, fpf3) field selector encodings.
 */
int
bcm_esw_field_group_set(int unit,
                        bcm_field_group_t group,
                        bcm_field_qset_t qset)
{
    bcm_field_qset_t        sel_qset[_FP_MAX_ENTRY_WIDTH];
    bcm_field_qset_t        qset_full, qset_old;
    bcm_pbmp_t              pbmp_old;
    _field_control_t        *fc;    
    _field_group_t          *fg;
    _field_stage_t          *stage_fc;            
    int                     re_create;
    bcm_field_group_mode_t  mode;
    uint8                   slice;
    int                     idx;
    int                     rv;

    FP_VVERB(("FP(unit %d) vverb:BEGIN bcm_field_group_set(group=%d)\n", unit, group));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* If no entries have been added to group try requested qset.  */
    if ((0 == fg->group_status.entry_count) && 
        (stage_fc->stage_id != _BCM_FIELD_STAGE_EXTERNAL)) {
        FP_VERB(("FP: bcm_field_group_set() with no entries\n"));

        /* Remember the group's current Qset, mode, and base slice. */
        qset_old = fg->qset;
        slice = fg->slices[0].slice_number;
        BCM_PBMP_ASSIGN(pbmp_old, fg->pbmp);

        rv = _bcm_esw_field_group_mode_get(fg->flags, &mode);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* Destroy the old group. */
        rv = bcm_esw_field_group_destroy(unit, group);

        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return rv;
        }

        /* Try to re-create the group with the requested Qset. */
        rv = bcm_esw_field_group_ports_create_mode_id(unit, pbmp_old, qset, 
                                                      slice, mode, group);

        /* On failure, re-create the old group. */
        if (BCM_FAILURE(rv)) {
            FP_ERR(("FP(unit %d) Error: new Qset won't work on group=%d.\n", unit, group));
            re_create = bcm_esw_field_group_ports_create_mode_id(unit, pbmp_old, 
                                                                 qset_old, slice,
                                                                 mode, group);
            if (BCM_FAILURE(re_create)) { /* Should never fail. */
                rv = BCM_E_INTERNAL;
            }
        }
        FP_UNLOCK(fc);
        return rv;
    }

    /*Expand qset with Internal qualifiers*/
    qset_old = fg->qset;
    fg->qset = qset;
    rv = _field_group_qset_update(unit, fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return rv;
    }
    qset = fg->qset;
    fg->qset = qset_old;


    /*
     * Handle cases where entries have been previously set in group.
     */

    /* Initialize local slice Qsets. */
    BCM_FIELD_QSET_INIT(qset_full);
    for (idx = 0; idx < _FP_MAX_ENTRY_WIDTH; idx++) {
        BCM_FIELD_QSET_INIT(sel_qset[idx]);


        rv = fc->functions.fp_selcode_to_qset(unit, stage_fc, fg,
                                              idx, &sel_qset[idx]);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return rv;
        }
        _field_qset_union(&sel_qset[idx], &qset_full, &qset_full);
    }

    /* If the requested Qset is supported by the current select codes, 
     * change the group's qset.
     */

    /* qset_full represents total Qset that current select codes support.
     * If the requested Qset is a subset of the full Qset, then the current
     * select codes will work. */
    if (_field_qset_is_subset(&qset, &qset_full)) {

        /* Increment the use-counts of any new UDFs. */
        _field_udf_usecount_update(fc->udf, &fg->qset, &qset);

        _field_qset_union(&fg->qset, &qset, &fg->qset);
        FP_VERB(("FP: Current select codes satisify new Qset\n"));

        /* Regenerate the qualifier info lists */
        rv= fc->functions.fp_qual_list_get(unit, stage_fc, fg);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return rv;
        }

        FP_UNLOCK(fc);
        return (BCM_E_NONE);
    }

    if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
        FP_UNLOCK(fc);
        return (BCM_E_RESOURCE);
    }

    /* 
     * Otherwise, use the current fg->sel_codes as a baseline. Try to
     * change any "don't care" FPFx settings to get the requested qset.
     */
    rv = _field_selcode_assign(unit, qset, 0, fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return rv;
    }

    /* Increment the use-counts of any new UDFs. */
    _field_udf_usecount_update(fc->udf, &fg->qset, &qset);

    _field_qset_union(&fg->qset, &qset, &fg->qset);

    /* Update the slices' Qsets and qualifier lists. */
    /* devices have qualifiers list generated 
       with select codes assignment. 
     */
    if (SOC_IS_EASYRIDER(unit)) {
        for (idx = 0; idx < _FP_MAX_ENTRY_WIDTH; idx++) {
            rv = _bcm_field_group_qualifiers_free(fg, idx);
            if (BCM_FAILURE(rv)) {
                FP_UNLOCK(fc);
                return rv;
            }
        }
    }

    /* Regenerate the qualifier info lists */
    rv= fc->functions.fp_qual_list_get(unit, stage_fc, fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return rv;
    }

    /* Write the new select codes to hardware. */
    rv = fc->functions.fp_group_install(unit, fg);

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

    FP_UNLOCK(fc);
    return rv;
}


/*
 * Function: bcm_esw_field_group_get
 *    
 * Purpose:
 *     Get the qualifier set for a previously created field group
 *     
 * Parameters:
 *     unit  - BCM device number
 *     port  - Port number
 *     group - Field group ID
 *     qset  - (OUT) Field qualifier set
 *     
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized.
 *     BCM_E_NOT_FOUND - Group ID not found in this unit
 *     BCM_E_PARAM     - qset is NULL
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_group_get(int unit,
                        bcm_field_group_t group,
                        bcm_field_qset_t *qset)
{
    _field_control_t       *fc;     /* Field control structure.    */
    _field_group_t         *fg;     /* Field group structure.      */
    int                    rv;      /* Operation return status.    */

    /* Input parameters check. */
    if (qset == NULL) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_group_get(unit, group, &fg);
    if (BCM_SUCCESS(rv)) {
        *qset = fg->qset;
    }

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_destroy
 *    
 * Purpose:
 *     Delete a field group
 *     
 * Parameters:
 *     unit - BCM device number
 *     port - Port number
 *     group - Field group
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Group ID not found in unit
 *     BCM_E_BUSY      - Entries not destroyed yet
 *     BCM_E_NONE      - Success
 *
 * Notes:
 *      All entries that uses this group should have been destroyed
 *      before calling this routine.
 *      Operation will fail if entries exist that uses this template
 */
int
bcm_esw_field_group_destroy(int unit, bcm_field_group_t group)
{
    _field_control_t    *fc;       /* Field control structure.        */
    _field_stage_t      *stage_fc; /* Stage field control structure.  */
    _field_group_t      *fg;      /* Group structure to free up       */ 
    int                 rv;       /* Operation return status.         */

    FP_VVERB(("FP(unit %d) vverb: bcm_field_group_destroy(group=%d)\n", unit, group));

    /* Find and validate field control. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Search the field control for the Group ID. */
    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        FP_ERR(("FP(unit %d) Error: Group=%d not found in device.\n", unit, group));
        return (rv);
    }
  
    /* okay, go ahead and free the group */

    /* Entries must be freed first (see note above). */
    if (0 != fg->group_status.entry_count) {
        FP_UNLOCK(fc);
        FP_ERR(("FP(unit %d) Error: entries still in group=%d.\n", unit, group));
        return (BCM_E_BUSY);
    }

    /* Get stage control for virtual map update. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        FP_ERR(("FP(unit %d) Error: Get stage (%d) control failed (%d).\n", 
                unit, fg->stage_id, rv));
        return (rv);
    }

    if (soc_feature(unit, soc_feature_field_virtual_slice_group) &&
        BCM_PBMP_EQ(fg->pbmp, fg->slices[0].pbmp)) {
        /*
         * If this is the only group in the slice 
         * flush group slices from virtual map.  
         */
        rv = _field_group_vmap_delete(unit, stage_fc, fg, TRUE);
    }

    _field_group_deinit(unit, fg);

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

    FP_UNLOCK(fc);
    return (rv);
}



/*
 * Function: bcm_esw_field_group_compress
 *
 * Purpose:
 *     Compress filed group entries, 
 *     in order to free slices used by the group.
 * Paramters:
 *     unit  - (IN) BCM device number
 *     group - (IN) Field group ID
 * Returns:
 *     BCM_E_XXX
 */

int
bcm_esw_field_group_compress(int unit, bcm_field_group_t group)
{
    _field_stage_t    *stage_fc;  /* Field group structure.   */
    _field_group_t          *fg;  /* Field group structure.   */
    _field_control_t        *fc;  /* Field control structure. */
    int                      rv;  /* Operation return status. */

    /* Lock the module. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get group control structure. */
    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get stage control structure. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

   rv = _field_group_compress(unit, fg, stage_fc);

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

   FP_UNLOCK(fc);
   return (rv);
}

/*
 * Function: bcm_esw_field_group_priority_set
 *
 * Purpose:
 *    Set field group priority. 
 * Paramters:
 *     unit     - (IN) BCM device number
 *     group    - (IN) Field group ID
 *     priority - (IN) Assigned group priority.
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_group_priority_set(int unit, bcm_field_group_t group,
                                 int priority)
{
    _field_group_t   *fg;      /* Field group structure.   */
    _field_control_t *fc;      /* Field control structure. */
    _field_stage_t   *stage_fc;/* Field stage control.     */
    int              rv;       /* Operation return status. */

    if (0 == soc_feature(unit, soc_feature_field_virtual_slice_group)) {
        return (BCM_E_UNAVAIL);
    }

    /* Lock the module. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get group control structure. */
    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get stage control structure. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Remove the group from virtual map . */
    rv = _field_group_vmap_delete(unit, stage_fc, fg, FALSE);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Assingn group priority. */
    fg->priority = priority;

    /* Reinstall group virtual map . */
    rv = _field_group_vmap_add(unit, stage_fc, fg);

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_priority_get
 *
 * Purpose:
 *    Get field group priority. 
 * Paramters:
 *     unit     - (IN) BCM device number
 *     group    - (IN) Field group ID
 *     priority - (OUT) Assigned group priority.
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_group_priority_get(int unit, bcm_field_group_t group, 
                                 int *priority)
{
    _field_group_t      *fg;      /* Field group structure.   */
    _field_control_t    *fc;      /* Field control structure. */
    int                  rv;      /* Operation return status. */

    if (0 == soc_feature(unit, soc_feature_field_virtual_slice_group)) {
        return (BCM_E_UNAVAIL);
    }

    /* Lock the module. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get group control structure. */
    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    *priority = fg->priority;

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/* 
 * Function:
 *     _field_group_status_calc
 * Purpose:
 *     Fill in the values of a group status struct.
 * Parameters:
 *     unit     - (IN) BCM device number. 
 *     fg       - (OUT)Group with up-to-date status structure
 * Returns:
 *     BCM_E_XXX
 */
STATIC int
_field_group_status_calc(int unit, _field_group_t *fg)
{
    bcm_field_group_status_t    *status;
    _field_stage_t              *stage_fc; /* Stage field control structure. */
    _field_slice_t              *fs;       /* Field slice control structure. */ 
    int                         count;     /* Generic purposes counter.      */
    int slice_index;
    bcm_port_config_t  port_config;

    /* Input parameters check. */
    if (NULL == fg) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN
        (_field_stage_control_get(unit, fg->stage_id, &stage_fc));

    status = &fg->group_status;

    /* Calculate total number of entries slices in group slices. */

    status->entries_total = 0;
    fs = &fg->slices[0];

    while (fs != NULL)
    {
        status->entries_total += fs->entry_count;
        fs = fs->next;
    }

    status->entries_free = 0;
    fs = &fg->slices[0];

    while (fs != NULL)
    {
        _field_entries_free_get(unit, fs, fg, &count);
        status->entries_free += count; 
        fs = fs->next;
    }

    fs = fg->slices;
    status->counters_total = fs->counters_count;
    status->counters_free  = _field_counter_free_get(stage_fc, fs);

    status->meters_total   = fs->meters_count; 
    status->meters_free    = _field_meter_free_get(stage_fc, fs);

    if (!(fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE))
    {
        fs += 1;

        status->counters_total += fs->counters_count;
        status->counters_free  += _field_counter_free_get(stage_fc, fs);

        status->meters_total  += fs->meters_count;
        status->meters_free   += _field_meter_free_get(stage_fc, fs);
    }

    if (stage_fc->flags & _FP_STAGE_AUTO_EXPANSION)
    {
        /* For expandable groups, find free slices and add the info */

        BCM_IF_ERROR_RETURN(bcm_esw_port_config_get(unit, &port_config));

        for (slice_index = 0; slice_index < stage_fc->tcam_slices;
            ++slice_index)
        {
            if (BCM_SUCCESS(_field_group_ports_validate(unit, stage_fc,
                slice_index, fg->flags, port_config.all)))
            {
                fs = stage_fc->slices + slice_index;

                status->entries_total += fs->entry_count;
                status->entries_free += fs->entry_count;

                status->counters_total += fs->counters_count;
                status->counters_free += fs->counters_count;

                status->meters_total += fs->meters_count;
                status->meters_free += fs->meters_count;
            }
        }
    }

    return (BCM_E_NONE);
}

/*
 * Function: bcm_esw_field_group_status_get
 *
 * Purpose:
 *     Get the number of used and available entries, counters, and
 *     meters for a field group.
 *
 * Paramters:
 *     unit - BCM device number
 *     group - Field group ID
 *     status - (OUT) Status structure
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit has not been intialized
 *     BCM_E_NOT_FOUND - Group ID not found on unit.
 *     BCM_E_PARAM     - *status is NULL
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_group_status_get(int unit,
                               bcm_field_group_t group,
                               bcm_field_group_status_t *status)
{
    _field_group_t      *fg;
    _field_control_t    *fc;
    int                  rv;

    if (status == NULL) {
        return (BCM_E_PARAM);
    }

    /* Lock the module. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }


    /* Update the numbers of free entries, meters and counters. */
    rv = _field_group_status_calc(unit, fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    *status = fg->group_status;
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function: bcm_esw_field_group_enable_set
 *    
 * Purpose:
 *     Enable/disable packet lookup on a group.
 *
 * Parameters:
 *     unit   - BCM device number
 *     enable - lookup enable!=0/disable==0 state of group
 *     group  - Field group ID
 *
 * Returns:
 *     BCM_E_NONE      - Success
 *     BCM_E_UNAVAIL   - BCM device does not have enable/disable feature
 *
 * Note:
 *     As a slice may have multiple groups, we just disable the entries
 *         of the particular group.
 */
int
bcm_esw_field_group_enable_set(int unit, bcm_field_group_t group, int enable)
{
    _field_group_t *fg;       /* Field group control structure. */
    _field_stage_t *stage_fc; /* Stage field control structure. */
    _field_control_t *fc;     /* Field control structure.       */
    int rv;                   /* Operation return status.       */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get field group descriptor. */
    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get field stage control structure. */
    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }
    
    /* Check slice enable feature support. */
    if (0 == (stage_fc->flags & _FP_STAGE_SLICE_ENABLE)) {
        FP_UNLOCK(fc);
        return (BCM_E_UNAVAIL);
    }

    /* Enable/disable primary slice. */
    rv = _field_fb_entries_enable_set(unit, fg, &fg->slices[0],enable);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* If needed, enable/disable secondary slice. */
    if (!(fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE)) {
        rv = _field_fb_entries_enable_set(unit, fg, &fg->slices[1], enable);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
    }

    /* If needed, enable/disable tertiary slice. */
    if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
        rv = _field_fb_entries_enable_set(unit, fg, &fg->slices[2], enable);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
    }

    if (enable) {
        fg->flags |= _FP_GROUP_LOOKUP_ENABLED; 
    } else {
        fg->flags &= ~_FP_GROUP_LOOKUP_ENABLED; 
    }

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: bcm_esw_field_group_enable_get
 *    
 * Purpose:
 *     Get the lookup enable/disable state of a group
 *
 * Parameters:
 *     unit   - BCM device number
 *     group  - Field group ID
 *     enable - (OUT) lookup enable/disable state of group
 *
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_group_enable_get(int unit, bcm_field_group_t group, int *enable)
{
    _field_group_t *fg;       /* Field group control structure. */
    _field_control_t *fc;     /* Field control structure.       */
    int rv;                   /* Operation return status.       */

    if (NULL == enable) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_group_get(unit, group, &fg);
    if (BCM_SUCCESS(rv)) {
        *enable = (fg->flags & _FP_GROUP_LOOKUP_ENABLED) ? TRUE : FALSE;
    }

    FP_UNLOCK(fc);
    return (rv);
}

/* Section: Range Checking */

/*
 * Function: bcm_esw_field_range_create_id
 *    
 * Purpose:
 *     Allocate a range checker and set its parameters.
 *
 * Parameters:
 *     unit   - (IN) BCM device number.
 *     range  - (IN) Range check ID to use.
 *     flags  - (IN) One or more of BCM_FIELD_RANGE_* flags.
 *     min    - (IN) Lower bounds of range to be checked, inclusive.
 *     max    - (IN) Upper bounds of range to be checked, inclusive.
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized.
 *     BCM_E_EXISTS    - Range ID already in use.
 *     BCM_E_RESOURCE  - Hardware range checkers all in use.
 *     BCM_E_NONE      - Success.
 *     BCM_E_XXX
 */

int
bcm_esw_field_range_create_id(int unit,
                              bcm_field_range_t range,
                              uint32 flags,
                              bcm_l4_port_t min,
                              bcm_l4_port_t max)
{
    int                 rv = BCM_E_UNAVAIL; /* Operation return value. */

#if defined(BCM_EASYRIDER_SUPPORT) || defined(BCM_FIREBOLT_SUPPORT)
    _field_control_t    *fc;            /* Field control structure. */  
    _field_stage_t      *stage_fc;      /* Stage field control info.*/
    _field_range_t      *fr;            /* Field range info.        */  
    int                 idx_max;        /* Loop termination index.  */
    int                 hw_index  = -1; /* Free/matching rang index.*/
    soc_mem_t           mem;            /* Range check memory.      */
    _field_stage_id_t   stage_id;       /* Pipeline stage id.       */
    SHR_BITDCL          *range_bmap;    /* Used indexes map.        */

    FP_VVERB(("FP(unit %d) vverb: BEGIN bcm_esw_field_range_create_id(range=%d, ", 
              unit, range));
    FP_VVERB(("flags=%#08x, min=%#x, max=%#x)\n", flags, min, max));
 
    /* Range type sanity check. */
    BCM_IF_ERROR_RETURN(_field_range_flags_check(unit, flags));

    if (flags & BCM_FIELD_RANGE_EXTERNAL) {
        mem = ESM_RANGE_CHECKm;
        stage_id = _BCM_FIELD_STAGE_EXTERNAL;
    } else {
        mem = FP_RANGE_CHECKm;
        stage_id = _BCM_FIELD_STAGE_INGRESS;
    }

    idx_max = soc_mem_index_max(unit, mem);  
    range_bmap = NULL;
    _FP_XGS3_ALLOC(range_bmap, SHR_BITALLOCSIZE(idx_max + 1), "FP valid ranges");
    if (NULL == range_bmap) {
        return (BCM_E_MEMORY);
    }

    rv = _field_control_get(unit, &fc);
    if (BCM_FAILURE(rv)) {
        sal_free(range_bmap);
        return (rv);
    }
    FP_LOCK(fc);

    rv = _field_stage_control_get(unit, stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        sal_free(range_bmap);
        return (rv);
    }


    /* Search existing ranges */
    for (fr = stage_fc->ranges; fr != NULL; fr = fr->next) {
        if (fr->rid == range) {
            FP_UNLOCK(fc);
            sal_free(range_bmap);
            FP_ERR(("FP(unit %d) Error: range_id=%d already exists.\n", unit, range));
            return (BCM_E_EXISTS);
        }

        /* Build maps of hardware in-use indexes. */
        if (fr->style == _FP_RANGE_STYLE_FIREBOLT) {
            SHR_BITSET(range_bmap, fr->hw_index);
        }

        /* Found an exisiting match so use it. */
        if (flags == fr->flags && min == fr->min && max == fr->max) {
            hw_index = fr->hw_index;
        }
    }

    /* If no match found, allocate a new hardware index. */
    if (hw_index < 0) {
        hw_index = soc_mem_index_min(unit, mem);
        for (; hw_index <= idx_max; hw_index++) {
            /* Found an unused FB style range checker */
            if (0 == SHR_BITGET(range_bmap, hw_index)) {
                break;
            }
        }

        /* No hardware indexes left. */
        if (hw_index == (idx_max + 1)) {
            FP_UNLOCK(fc);
            sal_free(range_bmap);
            FP_ERR(("FP(unit %d) Error: No hardware range checkers left.\n", unit));
            return (BCM_E_RESOURCE);
        }
    }

    /* Create a new range entry for the list */
    if ((fr = sal_alloc(sizeof (*fr), "fp_range")) == NULL) {
        FP_UNLOCK(fc);
        sal_free(range_bmap);
        return (BCM_E_MEMORY);
    }

    fr->flags    = flags;
    fr->rid      = range;
    fr->min      = min;
    fr->max      = max;
    fr->hw_index = hw_index;
    fr->style    = _FP_RANGE_STYLE_FIREBOLT;

    /* Try to program hardware */
#if defined(BCM_TRX_SUPPORT)
    if (SOC_IS_TRX(unit)) {
        rv = _bcm_field_trx_range_check_set(unit, hw_index, 
                                            flags, 1, min, max);
    } else 
#endif /* BCM_TRX_SUPPORT */
    {
        rv = _field_fb_er_range_check_set(unit, hw_index, flags, 1, min, max);
    }

    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        sal_free(range_bmap);
        sal_free(fr);
        FP_ERR(("FP(unit %d) Error: Device specific range check problem.\n", unit));
        return rv;
    }

    /* Add to list of range checkers. */

    {
        _field_range_t *p, **pp;

        /* List must be kept in acending order of hw_index -- is assumed by scache save
           and restore functions.
        */

        for (pp = &stage_fc->ranges; (p = *pp) && fr->hw_index > p->hw_index; pp = &p->next);

        (*pp = fr)->next = p;
    }

    FP_UNLOCK(fc);
    sal_free(range_bmap);

#endif /* BCM_EASYRIDER_SUPPORT || BCM_FIREBOLT_SUPPORT */
    return (rv);
}

/*
 * Function: bcm_esw_field_range_group_create_id
 *    
 * Purpose:
 *     Allocate an interface group range checker and set its parameters.
 *
 * Parameters:
 *     unit   - (IN) BCM device number.
 *     range  - (IN) Range check ID to use.
 *     flags  - (IN) One or more of BCM_FIELD_RANGE_* flags.
 *     min    - (IN) Lower bounds of range to be checked, inclusive.
 *     max    - (IN) Upper bounds of range to be checked, inclusive.
 *     group  - (IN) L3 interface group number.
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_EXISTS    - Range ID already in use
 *     BCM_E_RESOURCE  - Hardware range checkers all in use
 *     BCM_E_PARAM     - Invalid L3 interface group number
 *     BCM_E_NONE      - Success
 *     BCM_E_XXX
 */
int
bcm_esw_field_range_group_create_id(int unit,
                                    bcm_field_range_t range,
                                    uint32 flags,
                                    bcm_l4_port_t min,
                                    bcm_l4_port_t max,
                                    bcm_if_group_t group)
{
    int                 rv = BCM_E_UNAVAIL;     /* Operation return value. */
#if defined(BCM_EASYRIDER_SUPPORT) && defined(INCLUDE_L3)
    _field_control_t    *fc;                    /* Field Control structure. */
    _field_stage_t      *stage_fc;              /* Stage field control info.*/ 
    _field_range_t      *fr;                    /* Range info structure.    */
    bcm_l3_info_t       l3_info;

    FP_VVERB(("FP(unit %d) vverb:BEGIN bcm_esw_field_range_group_create_id(range=%d",
              unit, range));
    FP_VVERB(("flags=%#08x, min=%#x, max=%#x)\n", flags, min, max));

    if ((!SOC_IS_EASYRIDER(unit)) || 
        (!SOC_MEM_IS_VALID(unit, FP_TCP_UDP_PORT_RANGEm))
        || (flags & BCM_FIELD_RANGE_LOOKUP)) {
        return (BCM_E_UNAVAIL);
    }

    if (flags & BCM_FIELD_RANGE_SRCPORT && flags & BCM_FIELD_RANGE_DSTPORT) {
        FP_ERR(("FP(unit %d) Error: Can't select both source and destination.\n", unit));
        return (BCM_E_PARAM);
    }

    /* Get L3 info status structure. */
    BCM_IF_ERROR_RETURN(bcm_esw_l3_info(unit, &l3_info));

    if ((group < 0) || (group >= l3_info.l3info_max_intf_group)) {
        return (BCM_E_PARAM);
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get stage FP control structure. */
    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Search existing ranges */
    for (fr = stage_fc->ranges; fr != NULL; fr = fr->next) {
        if (fr->rid == range) {
            FP_UNLOCK(fc);
            return (BCM_E_EXISTS);
        }
    }

    /* Create a new range entry for the list */
    fr = sal_alloc(sizeof(_field_range_t), "fp_range");
    if (NULL == fr) {
        FP_UNLOCK(fc);
        return (BCM_E_MEMORY);
    }

    fr->flags    = flags;
    fr->rid      = range;
    fr->min      = min;
    fr->max      = max;
    fr->hw_index = group;
    fr->style    = _FP_RANGE_STYLE_EASYRIDER;

    /* The first half of FP_TCP_UDP_PORT_RANGEm are indexed by the 
     * output of L3_INTF_IGR_FILTER_LIST lookup. Fill in the
     * FP_TCP_UDP_PORT_RANGEm entry using the group number.
     */
    rv = bcm_er_field_range_check_set(unit, group, flags, min, max);
    if (BCM_FAILURE(rv)) {
        sal_free(fr);
        FP_UNLOCK(fc);
        return (rv);
    }

    /* The second half of FP_TCP_UDP_PORT_RANGEm are indexed by the 
     * output of L3_INTF_EGR_FILTER_LIST lookup. Fill in the
     * FP_TCP_UDP_PORT_RANGEm entry using the group number + max
     * number of inteface groups.
     */
    rv = bcm_er_field_range_check_set
        (unit, group + l3_info.l3info_max_intf_group, flags, min, max);
    if (BCM_FAILURE(rv)) {
        sal_free(fr);
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Add to list of range checkers. */
    fr->next = stage_fc->ranges;
    stage_fc->ranges = fr;

    FP_UNLOCK(fc);
#endif /* INCLUDE_L3 && BCM_EASYRIDER_SUPPORT */
    return rv;
}

/*
 * Function: bcm_esw_field_range_create
 *    
 * Purpose:
 *     Allocate a range checker and set its parameters.
 *
 * Parameters:
 *     unit   - BCM device number
 *     range  - (OUT) Range check ID, will not be zero
 *     flags  - One or more of BCM_FIELD_RANGE_* flags
 *     min    - Lower bounds of range to be checked, inclusive
 *     max    - Upper bounds of range to be checked, inclusive
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NONE      - Success
 *     BCM_E_XXX
 */

int
bcm_esw_field_range_create(int unit,
                           bcm_field_range_t *range,
                           uint32 flags,
                           bcm_l4_port_t min,
                           bcm_l4_port_t max)
{
    _field_control_t *fc;     /* Field control structure.       */
    int rv;                   /* Operation return status.       */

    FP_VVERB(("FP(unit %d) vverb:BEGIN bcm_esw_field_range_create( range->%#x", 
              unit, range));
    FP_VVERB(("flags=%#08x, min=%#x, max=%#x)\n", flags, min, max));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Range type sanity check. */
    BCM_IF_ERROR_RETURN(_field_range_flags_check(unit, flags));

    FP_LOCK(fc);

    rv = _field_range_create(unit, range, flags, min, max, -1);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_range_group_create
 *    
 * Purpose:
 *     Allocate a range checker and set its parameters.
 *
 * Parameters:
 *     unit   - BCM device number
 *     range  - (OUT) Range check ID, will not be zero
 *     flags  - One or more of BCM_FIELD_RANGE_* flags
 *     min    - Lower bounds of range to be checked, inclusive
 *     max    - Upper bounds of range to be checked, inclusive
 *     group  - L3 interface group number
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_PARAM     - Invalid L3 interface group number
 *     BCM_E_NONE      - Success
 *     BCM_E_XXX
 */

int
bcm_esw_field_range_group_create(int unit,
                                 bcm_field_range_t *range,
                                 uint32 flags,
                                 bcm_l4_port_t min,
                                 bcm_l4_port_t max,
                                 bcm_if_group_t group)
{
    int                 rv = BCM_E_UNAVAIL;
#if defined(INCLUDE_L3) && defined(BCM_EASYRIDER_SUPPORT)
    _field_control_t    *fc;
    bcm_l3_info_t       l3_info;

    if ((!SOC_IS_EASYRIDER(unit)) || 
        (!SOC_MEM_IS_VALID(unit, FP_TCP_UDP_PORT_RANGEm))) {
        return rv;
    }

    FP_VVERB(("FP(unit %d) vverb:BEGIN bcm_esw_field_range_group_create(range->%#x, ",
              unit, range));
    FP_VVERB(("flags=%#08x, min=%#x, max=%#x, group=%#x)\n", flags, min, max, group));


    rv = bcm_esw_l3_info(unit, &l3_info);
    if (BCM_FAILURE(rv)) {
        return rv;
    }

    if (group < 0 || group >= l3_info.l3info_max_intf_group) {
        return (BCM_E_PARAM);
    }


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);
    rv = _field_range_create(unit, range, flags, min, max, group);
    FP_UNLOCK(fc);
#endif /* INCLUDE_L3 && BCM_EASYRIDER_SUPPORT */
    return rv;
}

/*
 * Function: bcm_esw_field_range_get
 *    
 * Purpose:
 *     Get the TCP/UDP port for a range
 *
 * Parameters:
 *     unit  - (IN)  BCM device number.
 *     range - (IN)  Range check ID.
 *     flags - (OUT) Current range checker flags
 *     min   - (OUT) Lower bounds of range to be checked
 *     max   - (OUT) Upper bounds of range to be checked
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Invalid range ID
 *     BCM_E_NONE      - Success
 *     BCM_E_XXX
 */

int
bcm_esw_field_range_get(int unit,
                        bcm_field_range_t range,
                        uint32 *flags,
                        bcm_l4_port_t *min,
                        bcm_l4_port_t *max)
{
    _field_control_t    *fc;       /* Field control structure. */
    _field_stage_t      *stage_fc; /* Stage FP control info.   */
    _field_range_t      *fr;       /* Field range info.        */   
    int                 rv;        /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    for (fr = stage_fc->ranges; fr != NULL; fr = fr->next) {
        if (fr->rid == range) {
            break;
        }
    }

    if (fr == NULL) {
        /* Check if it is present in the External */
        rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_EXTERNAL, 
                                      &stage_fc);
        if (rv != BCM_E_NONE) {
            FP_UNLOCK(fc);
            return (BCM_E_NOT_FOUND);
        }
        for (fr = stage_fc->ranges; fr != NULL; fr = fr->next) {
            if (fr->rid == range) {
                break;
            }
        }
        if (fr == NULL) {
            FP_UNLOCK(fc);
            FP_ERR(("FP(unit %d) Error: range=%d not found.\n", unit, range));
            return (BCM_E_NOT_FOUND);
        }
    }

    if (flags != NULL) {
        *flags = fr->flags;
    }

    if (min != NULL) {
        *min = fr->min;
    }

    if (max != NULL) {
        *max = fr->max;
    }

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: bcm_esw_field_range_destroy
 *
 * Purpose:
 *     Deallocate a range
 *
 * Parameters:
 *     unit  - BCM device number
 *     range  - Range check ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Invalid range ID
 *     BCM_E_NONE      - Success
 *     BCM_E_XXX
 */

int
bcm_esw_field_range_destroy(int unit,
                            bcm_field_range_t range)
{
    _field_control_t    *fc;       
    _field_stage_t      *stage_fc;
    _field_range_t      *fr, *fr2, *fr_prev; 
    int                 use_count;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS,  &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Find matching entry */
    fr_prev = NULL;
    for (fr = stage_fc->ranges; fr != NULL; fr = fr->next) {
        if (fr->rid == range) {
            break;
        }
        fr_prev = fr;
    }

    if (fr == NULL) {
        /* Check if it is present in the External */
        rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_EXTERNAL, 
                                      &stage_fc);
        if (rv != BCM_E_NONE) {
            FP_UNLOCK(fc);
            return (BCM_E_NOT_FOUND);
        }
        fr_prev = NULL;
        for (fr = stage_fc->ranges; fr != NULL; fr = fr->next) {
            if (fr->rid == range) {
                break;
            }
            fr_prev = fr;
        }
        if (fr == NULL) {
            FP_UNLOCK(fc);
            FP_ERR(("FP(unit %d) Error: range=%d not found in.\n", unit, range));
            return (BCM_E_NOT_FOUND);
        }
    }

    if (fr->style == _FP_RANGE_STYLE_EASYRIDER) {
#ifdef BCM_EASYRIDER_SUPPORT
        if (SOC_IS_EASYRIDER(unit)) {
#ifdef INCLUDE_L3
            uint32 flags;
            bcm_l3_info_t l3_info;

            rv = bcm_esw_l3_info(unit, &l3_info);
            if (BCM_FAILURE(rv)) {
                FP_UNLOCK(fc); 
                return rv;
            }

            flags = (fr->flags & BCM_FIELD_RANGE_TCP) ? BCM_FIELD_RANGE_TCP :
                BCM_FIELD_RANGE_UDP;

            /* The first half of FP_TCP_UDP_PORT_RANGEm are indexed by the
             * output of L3_INTF_IGR_FILTER_LIST lookup. Fill in the
             * FP_TCP_UDP_PORT_RANGEm entry using the group number.
             */
            rv = bcm_er_field_range_check_set(unit, fr->hw_index, flags, 0, 0);

            if (BCM_SUCCESS(rv)) {
                /* The second half of FP_TCP_UDP_PORT_RANGEm are indexed by the
                 * output of L3_INTF_EGR_FILTER_LIST lookup. Fill in the
                 * FP_TCP_UDP_PORT_RANGEm entry using the group number + max
                 * number of inteface groups.
                 */
                rv = bcm_er_field_range_check_set(unit, fr->hw_index + 
                                                  l3_info.l3info_max_intf_group, 
                                                  flags, 0, 0);
            }
#endif /* INCLUDE_L3 */
        }
#endif /* BCM_EASYRIDER_SUPPORT */
    } else {

        /* See how many entries are using the same hardware index */
        use_count = 0;

        for (fr2 = stage_fc->ranges; fr2 != NULL; fr2 = fr2->next) {
            if (fr2->hw_index == fr->hw_index && fr->style == fr2->style) {
                use_count++;
            }
        }

        /* Clear from hardware if this is the only use */
        assert(use_count > 0);

        if (use_count == 1) {
            rv = BCM_E_UNAVAIL;

#if defined(BCM_TRX_SUPPORT)
            if (SOC_IS_TRX(unit)) {
                rv = _bcm_field_trx_range_check_set(unit, fr->hw_index,
                                                    (fr->flags & BCM_FIELD_RANGE_EXTERNAL),
                                                    0, 1, 0);
            } else 
#endif /* BCM_TRX_SUPPORT */
#if defined(BCM_EASYRIDER_SUPPORT) || defined(BCM_FIREBOLT_SUPPORT)
                if (SOC_IS_FBX(unit) || SOC_IS_EASYRIDER(unit)) {
                    rv = _field_fb_er_range_check_set(unit, fr->hw_index, 
                                                      0, 0, 0, 0);
                }
#endif /* BCM_EASYRIDER_SUPPORT || BCM_FIREBOLT_SUPPORT */

            if (BCM_FAILURE(rv)) {
                FP_UNLOCK(fc);
                return rv;
            }
        }
    }

    /* Remove from list and free */
    if (fr_prev == NULL) {
        stage_fc->ranges = fr->next;
    } else {
        fr_prev->next = fr->next;
    }

    FP_UNLOCK(fc);
    sal_free(fr);
    return (BCM_E_NONE);
}

/* Section: User Defined Field Management */

/*
 * Function: bcm_esw_field_udf_spec_set
 *
 * Purpose:
 *     Define a user-defined (4-byte) field 
 *
 * Parameters:
 *     unit      - BCM device number
 *     udf_spec  - Pointer to a user-defined field (UDF) definition structure
 *     flags     - One or more of BCM_FIELD_USER_* flags
 *     offset    - Word Offset (0..31)
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_PARAM     - Invalid flag or out-of-range offset
 *     BCM_E_UNAVAIL   - Feature unavailable on unit.
 *     BCM_E_NONE      - Success
 *     BCM_E_PARAM     - Invalid flags
 */

int 
bcm_esw_field_udf_spec_set(int unit,
                           bcm_field_udf_spec_t *udf_spec,
                           uint32 flags,
                           uint32 offset)
{
    _field_control_t    *fc;
    int                 rv;

    if ((NULL == udf_spec) || (offset > _FP_DATA_OFFSET_MAX)) {
        return (BCM_E_PARAM); 
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = fc->functions.fp_udf_spec_set(unit, udf_spec, flags, offset);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_udf_spec_get
 *
 * Purpose:
 *     Retrieve a specific packet format's settings from a
 *     udf_spec definition. 
 *
 * Parameters:
 *     unit      - BCM device number
 *     udf_spec  - Pointer to a user-defined field (UDF) definition structure
 *     flags     - (IN/OUT) One or more of BCM_FIELD_USER_* flags
 *     offset    - (OUT) Word Offset (0..31)
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_PARAM     - Invalid flag or out-of-range offset
 *     BCM_E_UNAVAIL   - Feature unavailable on unit.
 *     BCM_E_NONE      - Success
 *     BCM_E_XXX
 */

int 
bcm_esw_field_udf_spec_get(int unit,
                           bcm_field_udf_spec_t *udf_spec,
                           uint32 *flags,
                           uint32 *offset)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = fc->functions.fp_udf_spec_get(unit, udf_spec, flags, offset);
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function: bcm_esw_field_udf_create
 *
 * Purpose:
 *     Create a virtual UDF identifier, based on the requested udf_spec.
 *     On success, returns a udf_id.
 *
 * Parameters:
 *     unit      - BCM device number
 *     udf_spec  - Pointer to a user-defined field (UDF) definition structure
 *     udf_id    - Pointer to a UDF ID
 *
 * Returns:
 *     BCM_E_XXX
 */

int
bcm_esw_field_udf_create(int unit, bcm_field_udf_spec_t *udf_spec,
                         bcm_field_udf_t *udf_id)
{
    _field_control_t    *fc;
    int                 rv;

    if (udf_spec == NULL || udf_id == NULL) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv =  _field_udf_create(unit, udf_spec, udf_id);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_udf_create_id
 * 
 * Purpose:
 *     Configure a virtual UDF, using the designated udf_id.
 *
 * Parameters:
 *     unit      - BCM device number
 *     udf_spec  - Pointer to a user-defined field (UDF) definition structure
 *     udf_id    - UDF ID
 *
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_udf_create_id(int unit, bcm_field_udf_spec_t *udf_spec,
                            bcm_field_udf_t udf_id)
{
    _field_control_t    *fc;
    int                 rv;

    if (udf_spec == NULL) {
        FP_ERR(("FP(unit %d) Error: udf_spec is NULL\n", unit));
        return (BCM_E_PARAM);
    }

    if (udf_id >= BCM_FIELD_USER_NUM_UDFS) {
        FP_ERR(("FP(unit %d) Error: Invalid udf_id %d\n", unit, udf_id));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv =  _field_udf_create_id(unit, udf_spec, udf_id);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function: bcm_esw_field_udf_ethertype_set
 *
 * Purpose:
 *     Set the UDF Ethertype match value.
 *
 * Parameters:
 *     unit      - BCM device number
 *     index     - 0->7, Ethertype match index
 *     frametype - BCM_PORT_FRAMETYPE_xxx, 0 indicates disable entry
 *     ethertype - Ethertype value to match
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_PARAM     - Invalid index or frametype parameter
 *     BCM_E_UNAVAIL   - Feature unavailable on unit.
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_udf_ethertype_set(int unit, int index,
                                bcm_port_frametype_t frametype,
                                bcm_port_ethertype_t ethertype) 
{
    _field_control_t        *fc;        /* Field control structure.   */
    int                     rv;         /* Operation return status.   */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_fb_udf_ethertype_set(unit, index, frametype, ethertype);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_udf_ethertype_get
 *
 * Purpose:
 *     Get the UDF Ethertype match fields.
 *
 * Parameters:
 *     unit      - BCM device number
 *     index     - 0->7, Ethertype match index
 *     frametype - (OUT) BCM_PORT_FRAMETYPE_xxx
 *     ethertype - (OUT) Ethertype value to match
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_PARAM     - Invalid index or NULL pointer parameter
 *     BCM_E_UNAVAIL   - Feature unavailable on unit.
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_udf_ethertype_get(int unit, int index,
                                bcm_port_frametype_t *frametype,
                                bcm_port_ethertype_t *ethertype)
{
    _field_control_t        *fc;        /* Field control structure.   */
    int                     rv;         /* Operation return status.   */

    /* Input parameters check. */
    if ((NULL == frametype) || (NULL == ethertype)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_fb_udf_ethertype_get(unit, index, frametype, ethertype);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_udf_ipprotocol_set
 *
 * Purpose:
 *     Set the UDF IP Protocol match values.
 *
 * Parameters:
 *     unit      - BCM device number
 *     index     - Either 0 or 1, which of the two IpProtocol matches
 *     flags     - BCM_FIELD_USER_IP4/6 flags, 0 means clear entry
 *     proto     - protocol value to match
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_PARAM     - Invalid udf_id or NULL pointer parameter
 *     BCM_E_UNAVAIL   - Feature unavailable on unit.
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_udf_ipprotocol_set(int unit, int index, uint32 flags, uint8 proto)
{
    _field_control_t        *fc;            /* Field control structure.   */
    int                     rv;             /* Operation return status.   */
    int                     data_flags = 0; /* Data Qualifiers flags.     */

    switch (flags) {
        case 0:
            break;
        case BCM_FIELD_USER_IP4:
            data_flags |= BCM_FIELD_DATA_FORMAT_IP4;
            break;
        case BCM_FIELD_USER_IP6:
            data_flags |= BCM_FIELD_DATA_FORMAT_IP6;
            break;
        case (BCM_FIELD_USER_IP6 | BCM_FIELD_USER_IP4):
            data_flags |= (BCM_FIELD_DATA_FORMAT_IP4 | \
                    BCM_FIELD_DATA_FORMAT_IP6);
            break;
        default: 
            return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_fb_udf_ipprotocol_set(unit, index, data_flags, proto);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_udf_ipprotocol_get
 *
 * Purpose:
 *     Get the state of the UDF IP Protocol match fields.
 *
 * Parameters:
 *     unit      - BCM device number
 *     index     - Either 0 or 1, which of the two IpProtocol matches
 *     flags     - (OUT) BCM_FIELD_USER_IP4/6 flags, 0 means match disabled 
 *     proto     - (OUT) protocol value to match
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_PARAM     - Invalid index or NULL pointer parameter
 *     BCM_E_UNAVAIL   - Feature unavailable on unit.
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_udf_ipprotocol_get(int unit, int index, uint32 *flags,
                                 uint8 *proto)
{
    _field_control_t        *fc;            /* Field control structure.   */
    int                     rv;             /* Operation return status.   */
    uint32              data_flags = 0;     /* Data Qualifiers flags.     */

    /* Input parameters check. */
    if ((NULL == flags) || (NULL == proto)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_fb_udf_ipprotocol_get(unit, index, &data_flags, proto);

    FP_UNLOCK(fc);
    switch (data_flags) {
        case 0:
            *flags = 0;
            break;
        case BCM_FIELD_DATA_FORMAT_IP4:
            *flags = BCM_FIELD_USER_IP4;
            break;
        case BCM_FIELD_DATA_FORMAT_IP6:
            *flags = BCM_FIELD_USER_IP6; 
            break;
        case (BCM_FIELD_DATA_FORMAT_IP4 | BCM_FIELD_DATA_FORMAT_IP6):
            *flags = (BCM_FIELD_USER_IP4 | BCM_FIELD_USER_IP6);
            break;
        default:
            *flags = 0;
            break;
    }

    return (rv);
}

/*
 * Function: bcm_esw_field_udf_get
 *
 * Purpose:
 *     Retrieve the specified virtual UDF settings, returning them to the
 *     designated udf_spec.
 *
 * Parameters:
 *     unit      - BCM device number
 *     udf_spec  - Pointer to a user-defined field (UDF) definition structure
 *     udf_id    - UDF ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_PARAM     - Invalid udf_id or NULL pointer parameter
 *     BCM_E_UNAVAIL   - Feature unavailable on unit.
 *     BCM_E_NONE      - Success
 *     BCM_E_XXX
 */

int
bcm_esw_field_udf_get(int unit,
                          bcm_field_udf_spec_t *udf_spec,
                          bcm_field_udf_t udf_id)
{
    _field_control_t    *fc;
    int                 rv = BCM_E_UNAVAIL;

    if ( (udf_spec == NULL) ||
         (udf_id >= BCM_FIELD_USER_NUM_UDFS) ) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    if (!fc->udf[udf_id].valid) {
        FP_UNLOCK(fc);
        FP_ERR(("FP(unit %d) Error: udf=%d not configured.\n", unit, udf_id));
        return (BCM_E_NOT_FOUND);
    }
    rv = fc->functions.fp_udf_read(unit, udf_spec,
                                   fc->udf[udf_id].udf_num, 
                                   fc->udf[udf_id].user_num); 

    FP_UNLOCK(fc);
    return rv;
}

/*
 * Function: bcm_esw_field_udf_destroy
 *
 * Purpose:
 *     Destroy the specified virtual UDF, removing it from hardware.
 *     
 * Parameters:
 *     unit      - BCM device number
 *     udf_id    - UDF ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_PARAM     - Invalid udf_id
 *     BCM_E_EXISTS    - Requested UDF is being used
 *     BCM_E_UNAVAIL   - Feature unavailable on unit.
 *     BCM_E_NONE      - Success
 *     BCM_E_XXX
 */

int
bcm_esw_field_udf_destroy(int unit, bcm_field_udf_t udf_id)
{
    _field_control_t     *fc;
    int                  rv = BCM_E_UNAVAIL;
    bcm_field_udf_spec_t *udf_spec = NULL;

    if (udf_id >= BCM_FIELD_USER_NUM_UDFS) {
        FP_ERR(("FP(unit %d) Error: udf=%d out-of-range.\n", unit, udf_id));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    if (!fc->udf[udf_id].valid) {
        /* UDF already destroyed */
        FP_UNLOCK(fc);
        FP_ERR(("FP(unit %d) Error: udf=%d not configured.\n", unit, udf_id));
        return (BCM_E_PARAM);
    }
    if (fc->udf[udf_id].use_count) {
        /* UDF still in use; do not destroy */
        FP_UNLOCK(fc);
        return (BCM_E_EXISTS);
    }

    /* Install a "null" udf_spec to hardware */
    _FP_XGS3_ALLOC(udf_spec, sizeof(bcm_field_udf_spec_t), "UDF spec");
    if (NULL == udf_spec) {
        FP_UNLOCK(fc);
        return (BCM_E_MEMORY);
    }

    /* Clear udf spec in hw. */
    rv = fc->functions.fp_udf_delete(unit, udf_spec, 
                                     fc->udf[udf_id].udf_num, 
                                     fc->udf[udf_id].user_num); 
    sal_free(udf_spec);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return rv;
    }

    fc->udf[udf_id].valid = 0;

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qset_udf_get
 * Purpose:
 *      Get array of virtual UDF resources included in group qset.
 * Parameters:
 *      unit         - (IN) bcm device.
 *      qset         - (IN) Group qualifier set.
 *      udf_max      - (IN) Maximum qualifiers to fill.
 *      udf_arr      - (OUT) Udf ids array.
 *      udf_count    - (OUT) Number of udf ids filled in udf_arr.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_qset_udf_get(int unit, bcm_field_qset_t *qset, int udf_max,
                       int *udf_arr, int *udf_count) 
{
    _field_control_t *fc; /* Field control structure. */
    int idx;              /* Qset udf ids iterator.   */
    int count;            /* Filled entries count.    */

    /* Input parameters check. */
    if ((qset == NULL) || (udf_max <= 0) || 
        (NULL == udf_arr) || (NULL == udf_count)) {
        return BCM_E_PARAM;
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Reset caller provided array. */
    sal_memset(udf_arr, 0, udf_max * sizeof(int));

    /* Fill caller array. */
    count = 0;
    for (idx = 0; idx < BCM_FIELD_USER_NUM_UDFS; idx++) {
        /* Skip invalid udfs. */
        if (0 == fc->udf[idx].valid) {
            continue;
        }
        if (SHR_BITGET(qset->udf_map, idx)) {
            udf_arr[count] = idx;
            count++;
            if (count >= udf_max) {
                break;
            }
        }
    }
    *udf_count = count;

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: bcm_esw_field_qset_add_udf
 *
 * Purpose:
 *     Add a UDF definition to a qset 
 *
 * Parameters:
 *     unit     - BCM device number
 *     qset     - Pointer to a qset structure
 *     udf_id   - UDF ID to add to the qset
 *
 * Returns:
 *     BCM_E_INIT     - BCM unit not initialized 
 *     BCM_E_RESOURCE - Cannot add UDF (all UDFs used)
 *     BCM_E_NONE     - Success
 *     BCM_E_XXX
 */
int 
bcm_esw_field_qset_add_udf(int unit,
                           bcm_field_qset_t *qset,
                           bcm_field_udf_t udf_id)

{
    _field_control_t *fc;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc); 

    /* Parameter range checks, make sure that the specified UDF exists */
    if ( (qset == NULL) || (udf_id >= BCM_FIELD_USER_NUM_UDFS) ||
         (!fc->udf[udf_id].valid)) {
        FP_UNLOCK(fc);
        return BCM_E_NOT_FOUND;
    }

    SHR_BITSET(qset->udf_map, udf_id);

    /* 
     * Set the UserDefinedN bit. The BCM_FIELD_QSET_ADD/REMOVE macros
     * do not allow the user to set these bits directly, so the bit 
     * must be set manually.
     * These bits are used internally for FSEL calculation.
     */ 

    
    if (fc->udf[udf_id].udf_num == 0) {
#if defined(BCM_ENDURO_SUPPORT) || defined(BCM_KATANA_SUPPORT)
        if(SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit) || SOC_IS_KATANA(unit)) {
            BCM_FIELD_QSET_REMOVE_INTERNAL(*qset, _bcmFieldQualifyData2);
            BCM_FIELD_QSET_REMOVE_INTERNAL(*qset, _bcmFieldQualifyData3);
            if(udf_id == 3) {
                if(!SHR_BITGET(qset->udf_map, 0) && 
                  SHR_BITGET(qset->udf_map, 1) && 
                  !SHR_BITGET(qset->udf_map, 2)) {
                    /* Add both UDF1_31_0 and UDF1_95_64 */
                    BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData2);
                    BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData3);
                } else if( !SHR_BITGET(qset->udf_map, 0) && 
                  !SHR_BITGET(qset->udf_map, 1) && 
                  !SHR_BITGET(qset->udf_map, 2)){
                    /* Add UDF1_31_0 */
                    BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData2);
                } else {
                    /* Add UDF1_127_0 */
                    BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData0);
                }
            } else if(udf_id == 1) {
                if(SHR_BITGET(qset->udf_map, 3) && 
                  !SHR_BITGET(qset->udf_map, 0) && 
                  !SHR_BITGET(qset->udf_map, 2)) {
                    /* Add both UDF1_31_0 and UDF1_95_64 */
                    BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData2);
                    BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData3);
                } else if( !SHR_BITGET(qset->udf_map, 0) && 
                  !SHR_BITGET(qset->udf_map, 2) && 
                  !SHR_BITGET(qset->udf_map, 3)){
                    /* Add UDF1_95_64 */
                    BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData3);
                } else {
                    /* Add UDF1_127_0 */
                    BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData0);
                }
            } else {
                /* Add UDF1_127_0 */
                BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData0);
            }
        } else
#endif /* BCM_ENDURO_SUPPORT */     
        {        
            BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData0);
        }
    }
    else if (fc->udf[udf_id].udf_num == 1) {
        BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData1);
    } else {
        FP_ERR(("FP(unit %d) Error: No hardware UDF matching udf_id=%d", unit, udf_id));
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }
    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Section: Field Entries
 */

/*
 * Function: bcm_esw_field_entry_create
 *
 * Purpose:
 *     Create a blank entry based on a group. Automatically generate an entry
 *     ID.
 *
 * Parameters:
 *     unit  - BCM device number
 *     group - Field group ID
 *     entry - (OUT) New entry
 *
 * Returns:
 *     BCM_E_INIT        BCM unit not initialized
 *     BCM_E_NOT_FOUND   group not found in unit
 *     BCM_E_PARAM       *entry was NULL
 *     BCM_E_RESOURCE    No unused entries available
 *     BCM_E_XXX         Error from bcm_field_entry_create_id
 *
 * See Also:
 * bcm_field_entry_create_id
 */

int
bcm_esw_field_entry_create(int unit, bcm_field_group_t group,
                           bcm_field_entry_t *entry)
{
    _field_control_t    *fc;           /* Field control structure.    */
    _field_group_t      *fg;           /* Field group structure.      */
    _field_entry_t      *f_ent;        /* Field entry pointer.        */ 
    int                 rv;            /* Operation return status.    */

    if (entry == NULL) {
        FP_ERR(("FP(unit %d) Error: entry == NULL.\n", unit));
        return (BCM_E_PARAM);
    }
    
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Generate an entry ID.  */
    last_allocated_eid++;
    while (BCM_SUCCESS(_field_entry_get(unit, last_allocated_eid, 
                                        _FP_ENTRY_PRIMARY, &f_ent))) {
        last_allocated_eid++;
        if (_FP_ID_MAX == last_allocated_eid) {
            last_allocated_eid = _FP_ID_BASE;
        }
    }

    *entry = last_allocated_eid;
    rv = _field_entry_create_id(unit, group, *entry);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_entry_create_id
 *
 * Purpose:
 *     Create a blank entry group based on a group;
 *     allows selection of a specific slot in a slice
 *
 * Parameters:
 *     unit -  (IN) BCM device number.
 *     group - (IN) Field group ID.
 *     entry - (IN) Requested entry ID; must be in the range prio_min through
 *             prio_max as returned by bcm_field_group_status_get().
 * Returns:
 *     BCM_E_INIT      - unit not initialized
 *     BCM_E_EXISTS    - Entry ID already in use
 *     BCM_E_NOT_FOUND - Group ID not found in unit
 *     BCM_E_MEMORY    - allocation failure
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_entry_create_id(int unit,
                              bcm_field_group_t group,
                              bcm_field_entry_t entry)
{
    _field_control_t    *fc;          /* Field control structure.     */
        int                 rv;

        BCM_IF_ERROR_RETURN (_field_control_get(unit, &fc));
        FP_LOCK(fc);

    rv = _field_entry_create_id(unit, group, entry);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_entry_multi_get
 *
 * Purpose:
 *     Gets an array of a group's entry IDs
 *
 * Parameters:
 *     unit -  (IN) BCM device number.
 *     group - (IN) Field group ID.
 *     entry_size - (IN) Maximum number of entries to return.  Set to 0
 *                       to get the number of entries available
 *     entry_array - (OUT) Pointer to a buffer to fill with the array of
 *                         entry IDs.  Ignored if entry_size is 0
 *     entry_count - (OUT) Returns the number of entries returned in the
 *                         array, or if entry_size was 0, the number of
 *                         entries available

 * Returns:
 *     BCM_E_INIT      - unit not initialized
 *     BCM_E_NOT_FOUND - Group ID not found in unit
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_entry_multi_get(int unit, bcm_field_group_t group,
    int entry_size, bcm_field_entry_t *entry_array, int *entry_count)
{
    _field_control_t *fc;
        int entry_index;
    _field_group_t *fg_p;
    int rv;

    BCM_IF_ERROR_RETURN (_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_group_get(unit, group, &fg_p);

    if (BCM_SUCCESS(rv))
    {
        if (entry_count == NULL) {
            FP_ERR(("FP(unit %d) Error: entry_count == NULL.\n", unit));
            FP_UNLOCK(fc); 
            return (BCM_E_PARAM);
        }

        if (entry_size == 0)
        {
            *entry_count = fg_p->group_status.entry_count;
        }
        else
        {
            if (entry_array == NULL) {
                FP_ERR(("FP(unit %d) Error: entry_array == NULL.\n", unit));
                FP_UNLOCK(fc); 
                return (BCM_E_PARAM);
            }
            if (entry_size > fg_p->group_status.entry_count)
            {
                entry_size = fg_p->group_status.entry_count;
            }

            for (entry_index = 0;
                entry_index < entry_size; ++entry_index)
            {
                *entry_array = (fg_p->entry_arr[entry_index])->eid;

                ++entry_array;
            }

            *entry_count = entry_size;
        }
    }

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_entry_destroy
 *
 * Purpose:
 *     Deallocate the memory used to track an entry. This does not remove the
 *     entry from hardware if it has been installed. In order to remove an
 *     entry from hardware, call bcm_field_entry_remove() prior to calling this
 *     API.
 *
 * Parameters:
 *     unit  - BCM device number
 *     entry - Entry ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found
 *     BCM_E_XXX       - From bcm_field_counter_destroy() or
 *                       bcm_field_meter_destroy()
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_entry_destroy(int unit, bcm_field_entry_t entry)
{
        _field_entry_t      *f_ent;
        _field_group_t      *fg;        
        _field_control_t    *fc; 
        int                 rv;

        BCM_IF_ERROR_RETURN (_field_control_get(unit, &fc));
        FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
        if (BCM_FAILURE(rv)) {
           FP_UNLOCK(fc);
           return (rv);
        }

        fg = f_ent->group;

    /* Remove entry from hw before destroying sw image. */
    if (f_ent->flags & _FP_ENTRY_INSTALLED) {
        rv = bcm_esw_field_entry_remove(unit, entry);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return(rv);
        }
    }

    /* Destroy entry policers */
    rv = bcm_esw_field_entry_policer_detach_all(unit, entry);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return(rv);
    }

    /* Destroy entry policers */
    if (f_ent->statistic.flags & _FP_ENTRY_STAT_VALID) {
        rv = _field_entry_stat_detach(unit, f_ent, f_ent->statistic.sid);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return(rv);
        }
    }

        /* Destroy entry sw images. */
    rv = _field_entry_phys_destroy(unit, f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return(rv);
    }

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: bcm_esw_field_entry_destroy_all
 *
 * Purpose:
 *     Destroy all entries on a unit. It iterates over all slices in a unit.
 *     For each slice, If entries exist, it calls bcm_field_entry_destroy()
 *     using the Entry ID.
 *
 * Parameters:
 *     unit - (IN) BCM device number.
 *
 * Returns:
 *     BCM_E_XXX       - Error from bcm_field_entry_destroy().
 *     BCM_E_INIT      - BCM unit not initialized.
 *     BCM_E_NONE      - Success.
 */
int
bcm_esw_field_entry_destroy_all(int unit)
{
    _field_control_t    *fc;         /* Field control structure. */
    _field_group_t      *fg;         /* Field group info.        */
    _field_stage_t      *stage_fc;   /* Stage field control info.*/
    int                 rv;          /* Operation return status. */

    FP_VVERB(("FP(unit %d) vverb: bcm_field_entry_destroy_all()\n", unit));
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    fg = fc->groups;
    if (NULL == fg) {
        FP_UNLOCK(fc);
        return (BCM_E_NONE);
    }  

    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Scan unit's groups freeing each entry list. */
    for (; fg != NULL; fg = fg->next) {
        /* Destroy all entries in the group. */
        while(fg->group_status.entry_count) {
            rv =  bcm_esw_field_entry_destroy(unit, (fg->entry_arr[0])->eid);
            if (BCM_FAILURE(rv)) {
                FP_UNLOCK(fc);
                return (rv);
            }
        }
    }

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: bcm_esw_field_entry_copy
 *
 * Purpose:
 *     Create a copy of an existing entry. The new entry will be a member of
 *     the same group as the source entry.
 *
 * Parameters:
 *     unit      - BCM device number
 *     src_entry - Entry to copy
 *     dst_entry - (OUT) New entry
 *
 * Returns:
 *     BCM_E_INIT        BCM Unit not initialized
 *     BCM_E_NOT_FOUND   Source entry not found
 *     BCM_E_INTERNAL    No group exists for source entry ID.
 *     BCM_E_PARAM       dst_entry pointing to NULL
 *     BCM_E_RESOURCE    No destination entry available
 *     BCM_E_XXX         Error from bcm_field_entry_copy_id()
 */
int
bcm_esw_field_entry_copy(int unit,
                         bcm_field_entry_t src_entry,
                         bcm_field_entry_t *dst_entry)
{
    _field_control_t    *fc;
    _field_entry_t      *f_ent_src;
    _field_entry_t      *f_ent;
    int                 rv;

    if (dst_entry == NULL) {
        FP_ERR(("FP(unit %d) Error: dst_entry == NULL\n", unit));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, src_entry, _FP_ENTRY_PRIMARY, &f_ent_src);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Generate a destination Entry ID.  */
    *dst_entry = src_entry + 1;
    while (BCM_SUCCESS
           (_field_entry_get(unit, *dst_entry, _FP_ENTRY_PRIMARY, &f_ent))) {
        *dst_entry += 1;
    }

    rv = bcm_esw_field_entry_copy_id(unit, src_entry, *dst_entry);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_entry_copy_id
 *
 * Purpose:
 *     Create a copy of an existing entry with a requested ID
 *
 * Parameters:
 *     unit      - BCM device number
 *     src_entry - Source entry to copy
 *     dst_entry - Destination entry for copy
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized
 *     BCM_E_NOT_FOUND - Source Entry ID not found
 *     BCM_E_XXX       - Error code from bcm_field_entry_create_id()
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_entry_copy_id(int unit,
                            bcm_field_entry_t src_entry,
                            bcm_field_entry_t dst_entry)
{
    _field_control_t    *fc;
    _field_entry_t      *f_ent_src, *f_ent_dst;
    int                 parts_count;
    _field_action_t     *fa_src;
    int                 free_tcam = FALSE;
    int                 rv;
    int i;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_entry_get_by_id(unit, src_entry, &f_ent_src);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get number of entry parts . */
    rv = _bcm_field_entry_tcam_parts_count (unit, f_ent_src->group->flags, 
                                            &parts_count);
    BCM_IF_ERROR_RETURN(rv);


    /* Creating a new destination entry sets the unit, eid, gid, slice_idx,
     * ext, dirty, fs and next fields. Also, it correctly creates multiple
     * physical entry structures for wide-mode groups.
     */

    rv = bcm_esw_field_entry_create_id(unit, f_ent_src->group->gid, 
                                       dst_entry);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = _bcm_field_entry_get_by_id(unit, dst_entry, &f_ent_dst);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    for (i = 0; i < parts_count; i++) {
        if (NULL == f_ent_src[i].tcam.key) { 
            free_tcam = TRUE;
        }

        rv = _bcm_field_qual_tcam_key_mask_get(unit, f_ent_src + i);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* Entry create id might allocated tcam already. */
        rv = _bcm_field_qual_tcam_key_mask_free(unit, f_ent_dst + i);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* Copy qualification data. */
        sal_memcpy(&f_ent_dst[i].tcam, &f_ent_src[i].tcam, 
                   sizeof(_field_tcam_t));
        sal_memcpy(&f_ent_dst[i].extra_tcam, &f_ent_src[i].extra_tcam, 
                   sizeof(_field_tcam_t));

        f_ent_dst[i].tcam.key  = NULL;/* Do not copy allocated part.*/
        f_ent_dst[i].tcam.mask = NULL;/* Do not copy allocated part.*/
        f_ent_dst[i].extra_tcam.key  = NULL;/* Do not copy allocated part.*/
        f_ent_dst[i].extra_tcam.mask = NULL;/* Do not copy allocated part.*/
        if (f_ent_dst[i].fs->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
            f_ent_dst[i].tcam.key_hw = NULL;
            f_ent_dst[i].tcam.mask_hw = NULL;
        }

        if (f_ent_src[i].flags & _FP_ENTRY_USES_IPBM_OVERLAY) {
            f_ent_dst[i].flags |= _FP_ENTRY_USES_IPBM_OVERLAY;
        }

        /* Allocate tcam key and mask for destination entry. */
        rv = _bcm_field_qual_tcam_key_mask_get(unit,  f_ent_dst + i);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* Copy key and mask information. */
        sal_memcpy(f_ent_dst[i].tcam.key, f_ent_src[i].tcam.key, 
                   f_ent_src[i].tcam.key_size);
        sal_memcpy(f_ent_dst[i].tcam.mask, f_ent_src[i].tcam.mask, 
                   f_ent_src[i].tcam.key_size);

        if (f_ent_src[i].flags & _FP_ENTRY_USES_IPBM_OVERLAY) {
            sal_memcpy(f_ent_dst[i].extra_tcam.key,
                f_ent_src[i].extra_tcam.key,
                f_ent_src[i].extra_tcam.key_size);

            sal_memcpy(f_ent_dst[i].extra_tcam.mask,
                f_ent_src[i].extra_tcam.mask,
                f_ent_src[i].extra_tcam.key_size);
        }

        if (f_ent_dst[i].fs->stage_id == _BCM_FIELD_STAGE_EXTERNAL) {
            sal_memcpy(f_ent_dst[i].tcam.key_hw, 
                       f_ent_src[i].tcam.key_hw, 
                       f_ent_src[i].tcam.key_size);
            sal_memcpy(f_ent_dst[i].tcam.mask_hw, 
                       f_ent_src[i].tcam.mask_hw, 
                       f_ent_src[i].tcam.key_size);
        }

        if (free_tcam) {
            if (NULL != f_ent_src[i].tcam.key) {
                sal_free(f_ent_src[i].tcam.key);
                sal_free(f_ent_src[i].tcam.mask);
            }
            if (f_ent_src[i].flags & _FP_ENTRY_USES_IPBM_OVERLAY) {
                if (NULL != f_ent_src[i].extra_tcam.key) {
                    sal_free(f_ent_src[i].extra_tcam.key);
                    sal_free(f_ent_src[i].extra_tcam.mask);
                }
            }
            f_ent_src[i].tcam.key = f_ent_src[i].tcam.mask =
                f_ent_src[i].extra_tcam.key = f_ent_src[i].extra_tcam.mask =
                    NULL;
            free_tcam = FALSE;
        }
    }

#if defined(BCM_RAPTOR_SUPPORT) || defined (BCM_TRX_SUPPORT)
    if (soc_feature(unit, soc_feature_field_ingress_ipbm)) {
        BCM_PBMP_ASSIGN(f_ent_dst->pbmp.data, f_ent_src->pbmp.data);
        BCM_PBMP_ASSIGN(f_ent_dst->pbmp.mask, f_ent_src->pbmp.mask);
    }
#endif /* BCM_RAPTOR_SUPPORT || BCM_TRX_SUPPORT */

    /* Copy counter, if it exists. */
    if (f_ent_src->statistic.flags & _FP_ENTRY_STAT_VALID) {
        rv = bcm_esw_field_entry_stat_attach(unit, dst_entry,
                                             f_ent_src->statistic.sid);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
        /* Preseve original entry flags. */
        f_ent_dst->statistic.flags = (f_ent_src->statistic.flags &  \
            (_FP_ENTRY_STAT_VALID | _FP_ENTRY_STAT_EMPTY | 
             _FP_ENTRY_STAT_USE_EVEN | _FP_ENTRY_STAT_USE_ODD));
    }

    /*  Copy meter, if it exists. */
    for (i = 0; i < _FP_POLICER_LEVEL_COUNT; i++)  {
        if (f_ent_src->policer[i].flags & _FP_POLICER_VALID) {
            rv = bcm_esw_field_entry_policer_attach(unit, dst_entry, i,
                                                    f_ent_src->policer[i].pid);
            if (BCM_FAILURE(rv)) {
                FP_UNLOCK(fc);
                return (rv);
            }
        }
    }

    /* Copy source entry's action linked list.  */
    /* This also copies the counter specific actions */
    for (i = 0; i < parts_count; i++) {
        for (fa_src = f_ent_src[i].actions; 
             fa_src != NULL; 
             fa_src = fa_src->next) {
            rv = bcm_esw_field_action_add(unit, dst_entry, fa_src->action, 
                                          fa_src->param[0], fa_src->param[1]);
            if (BCM_FAILURE(rv)) {
                FP_UNLOCK(fc);
                return (rv);
            }
        }
    }
    f_ent_dst->flags     |= _FP_ENTRY_DIRTY;

    /* Set the destination entry's priority to the same as the source's. */
    rv = _field_entry_prio_set(unit, dst_entry, f_ent_src->prio);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_entry_install
 *
 * Purpose:
 *     Install a entry into the hardware tables.
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Entry to install
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found on unit.
 *     BCM_E_XXX       - Error from _field_XX_tcam_policy_install()
 *     BCM_E_NONE      - Success
 *
 * Notes:
 *     Qualifications should be made and actions should be added
 *     prior to installing the entry.
 */
int
bcm_esw_field_entry_install(int unit, bcm_field_entry_t entry)
{
    _field_control_t    *fc;    /* Field control structure. */
    _field_entry_t      *f_ent; /* Field entry structure.   */
    int                 rv;     /* Operation return status. */
    int                 dirty;  /* Field entry dirty flag.  */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return rv;
    }

    rv = _field_entry_dirty(unit, f_ent, &dirty);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Write the TCAM and Policy entry */
    if (dirty) {
        rv = _field_tcam_policy_install(unit, entry);
    } else {
        rv = BCM_E_NONE;
    }

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

    FP_UNLOCK(fc);
    return rv;
}

/*
 * Function:
 *
 * Purpose:
 *     Re-install a entry into the hardware tables.
 *
 * Parameters:
 *     unit  - (IN) BCM device number
 *     entry - (IN) Entry to install
 *
 * Returns:
 *     BCM_E_XXX   
 */
int
bcm_esw_field_entry_reinstall(int unit, bcm_field_entry_t entry)
{
    _field_control_t    *fc;    /* Field control structure. */
    _field_entry_t      *f_ent; /* Field entry structure.   */
    int                 rv;     /* Operation return status. */
    int                 dirty = 0;  /* Field entry dirty flag.  */
    int                 action_dirty = 0;  /* Field entry action dirty flag. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return rv;
    }

    /* Check if only action has been modifed for this entry. */
    rv = _field_entry_action_dirty(unit, f_ent, &action_dirty);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Check if any parameter has been modified for this entry. */
    rv = _field_entry_dirty(unit, f_ent, &dirty);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    if (action_dirty) {
        /* Write Policy table for this entry. */
        rv = _field_tcam_policy_reinstall(unit, entry);
    } else if (dirty) {
        /* Write TCAM and Policy table for this entry. */
        rv = _field_tcam_policy_install(unit, entry);
    } else {
        rv = BCM_E_NONE;
    }

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

    FP_UNLOCK(fc);
    return rv;
}


/*
 * Function: bcm_esw_field_entry_remove
 *
 * Purpose:
 *     Remove an entry from the hardware tables.
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Entry to remove
 *
 * Returns:
 *     BCM_E_XXX
 *
 * Notes:
 *     This does not destroy the entry; it only uninstalls it from
 *     any hardware tables. To deallocate the memory used by the entry call
 *     bcm_field_entry_destroy.
 */
int
bcm_esw_field_entry_remove(int unit, bcm_field_entry_t entry)
{
    _field_control_t    *fc;         /* Field control structure. */
    int                 rv;          /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv =  _field_entry_remove(unit, fc, entry);

#ifdef BCM_WARM_BOOT_SUPPORT
    SOC_CONTROL_LOCK(unit);
    SOC_CONTROL(unit)->scache_dirty = 1;
    SOC_CONTROL_UNLOCK(unit);
#endif

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_group_install
 *
 * Purpose:
 *     Install all of a group's entries into the hardware tables.
 *
 * Parameters:
 *     unit - BCM device number
 *     group - Group to install
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Group ID not found on unit.
 *     BCM_E_XXX       - Error from bcm_esw_field_entry_install()
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_group_install(int unit, bcm_field_group_t group)
{
    _field_control_t *fc;
    _field_group_t *fg_p;
    int entry_index;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    BCM_IF_ERROR_RETURN(_field_group_get(unit, group, &fg_p));

    for (entry_index = 0;
        entry_index < fg_p->group_status.entry_count;
        ++entry_index)
    {
        BCM_IF_ERROR_RETURN(bcm_esw_field_entry_install(unit,
            fg_p->entry_arr[entry_index]->eid));
    }

    FP_UNLOCK(fc);

    return BCM_E_NONE;
}

/*
 * Function: bcm_esw_field_group_remove
 *
 * Purpose:
 *     Remove all of a group's entries from the hardware tables.
 *
 * Parameters:
 *     unit - BCM device number
 *     group - Group to install
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Group ID not found on unit.
 *     BCM_E_XXX       - Error from _field_entry_remove()
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_group_remove(int unit, bcm_field_group_t group)
{
    _field_control_t *fc;
    _field_group_t *fg_p;
    int entry_index;
        int rv = BCM_E_NONE;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_group_get(unit, group, &fg_p);
    if (BCM_FAILURE(rv))
    {
        FP_UNLOCK(fc);
        return (rv);
    }

    for (entry_index = 0;
        entry_index < fg_p->group_status.entry_count;
        ++entry_index)
    {
        rv = _field_entry_remove(unit, fc,
                        fg_p->entry_arr[entry_index]->eid);
        if (BCM_FAILURE(rv))
        {
            FP_UNLOCK(fc);
            return (rv);
        }
    }

    FP_UNLOCK(fc);

    return (rv);
}

/*
 * Function: bcm_esw_field_entry_prio_get
 *
 * Purpose:
 *     Gets the priority within the group of the entry.
 *
 * Parameters:
 *     unit   - BCM device number
 *     entry  - Field entry to operate on
 *     prio   - (OUT) priority of entry
 *
 * Returns:
 *     BCM_E_NONE       - Success
 *     BCM_E_PARAM      - prio pointing to NULL
 *     BCM_E_NOT_FOUND  - Entry ID not found on unit
 */
int
bcm_esw_field_entry_prio_get(int unit, bcm_field_entry_t entry, int *prio)
{
    _field_entry_t      *f_ent;
    _field_control_t    *fc;         /* Field control structure. */
    int                 rv;          /* Operation return status. */

    if (prio == NULL) {
        FP_ERR(("FP(unit %d) Error: prio==NULL\n", unit));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    *prio = f_ent->prio;

    FP_UNLOCK(fc);
    return (rv);
}
/*
 * Function: bcm_esw_field_entry_prio_set
 *
 * Purpose:
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Field entry to operate on
 *
 * Returns:
 *     BCM_E_NONE       Success
 *
 * Notes: 
 *     The earlier checks guarantee that there is a free slot somewhere
 *     i.e. in one of the alloted slices for the group.
 */
int
bcm_esw_field_entry_prio_set(int unit, bcm_field_entry_t entry, int prio)
{
    _field_control_t    *fc;
    int rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_prio_set(unit, entry, prio);

    FP_UNLOCK(fc);
    return (rv);
}
/* Section: Field Qualifiers  */

/*
 * Function: bcm_esw_field_qualify_clear
 *
 * Purpose:
 *     Remove all field qualifications from a filter entry
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Field entry to operate on
 *
 * Returns:
 *     BCM_E_INIT       BCM Unit not initialized.
 *     BCM_E_NOT_FOUND  Entry ID not found in unit.
 *     BCM_E_NONE       Success
 */
int
bcm_esw_field_qualify_clear(int unit,
                            bcm_field_entry_t entry)
{
    int               parts_count;  /* Tcam entry parts count. */
    _field_entry_t    *f_ent;       /* Field entry pointer.    */
    _field_group_t    *fg;          /* Field group pointer.    */
    _field_control_t  *fc;          /* Field control structure.*/
    int               idx;          /* Entry parts iterator.   */
    int               rv;           /* Operation return status.*/

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_entry_get_by_id(unit, entry, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    fg = f_ent->group;

    /* Get number of entry parts we have to read. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv); 
    }

    for (idx = 0; idx < parts_count; idx++) {
        /* Free allocated portion of sw tcam image. */
        _bcm_field_qual_tcam_key_mask_free(unit, f_ent + idx);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* Reset sw tcam image. */
        sal_memset(&f_ent[idx].tcam, 0, sizeof(_field_tcam_t));

        /* Get tcam key and mask. */
        rv = _bcm_field_qual_tcam_key_mask_get(unit, f_ent + idx);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv); 
        }

        /* Reset tcam key and mask. */
        sal_memset(f_ent[idx].tcam.key, 0, f_ent[idx].tcam.key_size);
        sal_memset(f_ent[idx].tcam.mask, 0, f_ent[idx].tcam.key_size);

        if ((fg->stage_id == _BCM_FIELD_STAGE_INGRESS) && 
            SOC_MEM_FIELD_VALID(unit, FP_TCAMm, F4f)) {
            f_ent[idx].tcam.f4 = 0;
            f_ent[idx].tcam.f4_mask = 0;
        }

        if (f_ent[idx].extra_tcam.key != NULL)
        {
            sal_memset(f_ent[idx].extra_tcam.key, 0,
                f_ent[idx].extra_tcam.key_size);

            sal_memset(f_ent[idx].extra_tcam.mask, 0,
                f_ent[idx].extra_tcam.key_size);
        }

        /* Reset IPBM if aplicable */
#if defined(BCM_RAPTOR_SUPPORT) || defined (BCM_TRX_SUPPORT)
        if ((_BCM_FIELD_STAGE_INGRESS == fg->stage_id) && 
            (soc_feature(unit, soc_feature_field_ingress_ipbm))) {
            BCM_PBMP_CLEAR(f_ent[idx].pbmp.data);
            BCM_PBMP_CLEAR(f_ent[idx].pbmp.mask);
        }
#endif

        /* Initialize entry qualifiers based on group flags. */
        rv = _field_entry_qualifiers_init(unit, f_ent);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv); 
        }

        /* Mark entry for reinstall. */
        f_ent[idx].flags |= _FP_ENTRY_DIRTY;
    }
    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualifier_delete
 * Purpose:
 *      Remove match criteria from a field processor entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      qual_id - (IN) BCM field qualifier id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 *   The assumption is that all qualifiers are less then 128 bit.
 */
int 
bcm_esw_field_qualifier_delete(int unit, bcm_field_entry_t entry, 
                               bcm_field_qualify_t qual_id)
{
    _bcm_field_qual_offset_t *q_offset;/* Qualifier offset in tcam. */
    _bcm_field_qual_data_t    q_data;  /* Qualifier match data.     */ 
    _bcm_field_qual_data_t    q_mask;  /* Qualifier match mask.     */
    _field_control_t          *fc;     /* Field control structure.  */
    _field_entry_t            *f_ent;  /* Field entry structure.    */
    int                       rv;      /* Operation return status.  */

    sal_memset(q_data, 0, sizeof(_bcm_field_qual_data_t));
    sal_memset(q_mask, 0, sizeof(_bcm_field_qual_data_t));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual_id, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    switch(qual_id) {
#if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_TRX_SUPPORT)
        case bcmFieldQualifyInPort:
        case bcmFieldQualifyInPorts:
            BCM_PBMP_CLEAR(f_ent->pbmp.data);
            BCM_PBMP_CLEAR(f_ent->pbmp.mask);
            break;
#endif /* BCM_RAPTOR_SUPPORT || BCM_TRX_SUPPORT */
#if defined(BCM_FIREBOLT2_SUPPORT)
        case bcmFieldQualifyDrop:
            f_ent->tcam.drop      = 0;
            f_ent->tcam.drop_mask = 0;
            break;
#endif /* BCM_FIREBOLT2_SUPPORT */
        case bcmFieldQualifyHiGig:
            f_ent->tcam.higig      = 0;
            f_ent->tcam.higig_mask = 0;
            break;
        case bcmFieldQualifyIpType:
            f_ent->tcam.ip_type = bcmFieldIpTypeAny;
            break;
        default:
            break;
    }

    /* Get entry qualifier offset in tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual_id, &q_offset);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Reset qualifier data and mask in the tcam. */
    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, q_data, q_mask);

    f_ent->flags |= _FP_ENTRY_DIRTY;

    FP_UNLOCK(fc);
    return rv; 
}


/*
 * Function: bcm_esw_field_qualify_XXX (class of routines)
 *
 * Purpose:
 *     Add a field qualification to a filter entry.
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Field entry to operate on
 *     data - Data to qualify with (type varies)
 *     mask - Mask to qualify with (type is same as for data)
 *
 * Returns:
 *     BCM_E_INIT       BCM Unit not initialized.
 *     BCM_E_NOT_FOUND  Entry ID not found in unit.
 *     BCM_E_XXX        Other errors
 */

int
bcm_esw_field_qualify_InPort(int unit, bcm_field_entry_t entry,
                             bcm_port_t data, bcm_port_t mask)
{
    _field_control_t *fc;
    _field_entry_t   *f_ent;
    _field_group_t   *fg;
    int              rv;

    if (BCM_GPORT_IS_SET(data)) {
        rv = _field_qualifier_gport_resolve(unit, data, mask, 
                                            &data, NULL, NULL);
        BCM_IF_ERROR_RETURN(rv);
    }
    if (0 == SOC_PORT_VALID(unit, data)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_entry_qual_get(unit, entry, bcmFieldQualifyInPort, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    fg = f_ent->group;

#if defined(BCM_RAPTOR_SUPPORT) || defined (BCM_TRX_SUPPORT)
    if ((_BCM_FIELD_STAGE_INGRESS == fg->stage_id) && 
        (soc_feature(unit, soc_feature_field_ingress_ipbm))) {
        bcm_pbmp_t pbmp_data, pbmp_mask;
        bcm_port_config_t  port_config;/* Device port config structure.*/

        /* Read device port configuration. */ 
        rv = bcm_esw_port_config_get(unit, &port_config);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* pbmp_mask: All 1's
         * pbmp_data: Qualify *only* on the port requested 
         *     Raptor, Triumph does not have a separate field to 
         *     qualify on InPort  So need to use the IPBM 
         *     Also the "bcm_port_t mask" is assumed to be 1. */
        BCM_PBMP_CLEAR(pbmp_data);
        BCM_PBMP_ASSIGN(pbmp_mask, port_config.all);
        BCM_PBMP_PORT_SET(pbmp_data, data);

        BCM_PBMP_ASSIGN(f_ent->pbmp.data, pbmp_data);
        BCM_PBMP_ASSIGN(f_ent->pbmp.mask, pbmp_mask);

        /* Add loopback port to ipbm mask to avoid false ingress port match */
        if (soc_feature(unit, soc_feature_internal_loopback)) {
            BCM_PBMP_OR(f_ent->pbmp.mask, PBMP_LB(unit));
        }
        f_ent->flags |= _FP_ENTRY_DIRTY;

        FP_UNLOCK(fc);
        return (BCM_E_NONE);
    }
#endif /* BCM_RAPTOR_SUPPORT || BCM_TRX_SUPPORT */

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInPort, data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_OutPort(int unit, bcm_field_entry_t entry,
                             bcm_port_t data, bcm_port_t mask)
{
    _field_control_t *fc;
    int              rv;

    if (BCM_GPORT_IS_SET(data)) {
        rv = _field_qualifier_gport_resolve(unit, data, mask, 
                                            &data, NULL, NULL);
        BCM_IF_ERROR_RETURN(rv);
    }
    if (0 == SOC_PORT_VALID(unit, data)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyOutPort, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InPorts(int unit, bcm_field_entry_t entry,
                              bcm_pbmp_t data, bcm_pbmp_t mask)
{
    _field_control_t *fc;
    int              rv;
    int port;

    /* Check if all data ports are valid on this device */
    SOC_PBMP_ITER(data, port) {
        if (!SOC_PORT_VALID(unit, port)) {
            return BCM_E_PARAM;
        }
    }

    /*
     * Check and clear invalid ports in the mask. 
     */ 
    SOC_PBMP_ITER(mask, port) {
        if (!SOC_PORT_VALID(unit, port)) {
            BCM_PBMP_PORT_REMOVE(mask, port);
        }
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

#if defined(BCM_RAPTOR_SUPPORT) || defined (BCM_TRX_SUPPORT)
    if (soc_feature(unit, soc_feature_field_ingress_ipbm)) {
        _field_entry_t *f_ent;
        _field_group_t *fg;

        rv = _bcm_field_entry_qual_get(unit, entry, 
                                       bcmFieldQualifyInPorts, &f_ent);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* Confirm that InPorts is in group's Qset. */
        fg = f_ent->group;
        if (!BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyInPorts)) {
            FP_ERR(("FP(unit %d) Error: InPorts not in entry=%d Qset.\n", unit, entry));
            FP_UNLOCK(fc);
            return (BCM_E_PARAM);
        }

        /* Add data & mask to entry. */ 
        BCM_PBMP_ASSIGN(f_ent->pbmp.data, data);
        BCM_PBMP_ASSIGN(f_ent->pbmp.mask, mask);

        /* Add loopback port to ipbm mask to avoid false ingress port match */
        if (soc_feature(unit, soc_feature_internal_loopback)) {
            BCM_PBMP_OR(f_ent->pbmp.mask, PBMP_LB(unit));
        }
        f_ent->flags |= _FP_ENTRY_DIRTY;

        FP_UNLOCK(fc);
        return (BCM_E_NONE);
    }
#endif /* BCM_RAPTOR_SUPPORT || BCM_TRX_SUPPORT */

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInPorts,
                          SOC_PBMP_WORD_GET(data, 0),
                          SOC_PBMP_WORD_GET(mask, 0));
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_OutPorts(int unit, bcm_field_entry_t entry,
                               bcm_pbmp_t data, bcm_pbmp_t mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyOutPorts,
                          SOC_PBMP_WORD_GET(data, 0),
                          SOC_PBMP_WORD_GET(mask, 0));
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_Drop(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

#ifdef BCM_FIREBOLT2_SUPPORT
    /* 
     * FB2 has Drop at two places:
     *     one is FIXED (always used), and the other based on selectors. 
     * The one based on selector is thus redundant!!!
     */
    if (SOC_IS_FIREBOLT2(unit)) {
        _field_entry_t      *f_ent;
        _field_group_t      *fg;

        rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* Confirm that Drop is in group's Qset. */
        fg = f_ent->group;
        if (!BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyDrop)) {
            FP_ERR(("FP(unit %d) Error: Drop not in entry=%d Qset.\n", unit));
            FP_UNLOCK(fc);
            return (BCM_E_PARAM);
        }

        /* Add data & mask to entry. */
        f_ent->tcam.drop      = data;
        f_ent->tcam.drop_mask = mask;

        FP_UNLOCK(fc);
        return (BCM_E_NONE);
    }
#endif /* BCM_FIREBOLT2_SUPPORT */    

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDrop,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* Note:
 *    Deprecated in favor of bcm_field_qualify_SrcPort().
 */
int
bcm_esw_field_qualify_SrcModid(int unit, bcm_field_entry_t entry,
                               bcm_module_t data, bcm_module_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int isLocal;               /* Local modid flag.        */
    int              rv;       /* Operation return status. */

    if (BCM_GPORT_IS_SET(data)) {
        rv = _field_qualifier_gport_resolve(unit, data, mask, 
                                            NULL, &data, NULL);
        BCM_IF_ERROR_RETURN(rv);
    } else {
        if ((NUM_MODID(unit) > 1) && (SOC_IS_TR_VL(unit)) ) {
            if (mask == BCM_FIELD_EXACT_MATCH_MASK) {
                rv = _bcm_esw_modid_is_local(unit, data, &isLocal);
                BCM_IF_ERROR_RETURN(rv);
                if (isLocal) {
                    rv = bcm_esw_stk_my_modid_get(unit, &data);
                    BCM_IF_ERROR_RETURN(rv);
                }
            } else {
                return (BCM_E_PARAM);
            }
        }
    }
   
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifySrcModid,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* Note:
 *    Deprecated in favor of bcm_field_qualify_SrcPort().
 */
int
bcm_esw_field_qualify_SrcPortTgid(int unit, bcm_field_entry_t entry,
                                  bcm_port_t data, bcm_port_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);
    rv = _field_qualify_PortTgid(unit,entry, bcmFieldQualifySrcPortTgid, 
                                 data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_SrcPort(int unit, bcm_field_entry_t entry,
                              bcm_module_t data_modid,
                              bcm_module_t mask_modid,
                              bcm_port_t   data_port,
                              bcm_port_t   mask_port)
{
    _field_control_t *fc;      /* Field control structure. */
    bcm_module_t     mymodid;  /* Local module id.         */
    int              isLocal;  /* Local module id flag.    */
    int              rv;       /* Operation return status. */

    if (BCM_GPORT_IS_SET(data_port)) {
        rv = _field_qualifier_gport_resolve(unit, data_port, mask_port, 
                                            &data_port, &data_modid, NULL);
        BCM_IF_ERROR_RETURN(rv);
    } else {
        if ((NUM_MODID(unit) > 1) && (SOC_IS_TR_VL(unit)) ) {
            if ((data_port < 0) || (data_port > 31)) {
                return (BCM_E_PARAM);
            }
            if ((mask_modid == BCM_FIELD_EXACT_MATCH_MASK) && 
                (mask_port  == BCM_FIELD_EXACT_MATCH_MASK)) {
                rv = _bcm_esw_modid_is_local(unit, data_modid, &isLocal);
                BCM_IF_ERROR_RETURN(rv);
                if (isLocal) {
                    rv = bcm_esw_stk_my_modid_get(unit, &mymodid);
                    BCM_IF_ERROR_RETURN(rv);
                    while (mymodid != data_modid) {
                       data_modid -= 1;
                       data_port += 32;
                    }
                }
            } else {
                return (BCM_E_PARAM);
            }
        }
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_Port(unit, entry, data_modid, mask_modid,
                             data_port, mask_port, bcmFieldQualifySrcPort);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_SrcTrunk(int unit, bcm_field_entry_t entry,
                              bcm_trunk_t data, bcm_trunk_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    if (BCM_GPORT_IS_SET(data)) {
        rv = _field_qualifier_gport_resolve(unit, data, mask, 
                                           NULL, NULL, &data);
        BCM_IF_ERROR_RETURN(rv);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_Trunk(unit, entry, data, mask,
                              bcmFieldQualifySrcTrunk);
    FP_UNLOCK(fc);
    return (rv);
}


/* Note:
 *    Deprecated in favor of bcm_field_qualify_DstPort().
 */
int
bcm_esw_field_qualify_DstModid(int unit, bcm_field_entry_t entry,
                               bcm_module_t data, bcm_module_t mask)
{
    int isLocal;               /* Local modid flag.        */
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    if (BCM_GPORT_IS_SET(data)) {
        rv = _field_qualifier_gport_resolve(unit, data, mask, 
                                           NULL, &data, NULL);
        BCM_IF_ERROR_RETURN(rv);
    } else {
        if ((NUM_MODID(unit) > 1) && (SOC_IS_TR_VL(unit)) ) {
            if (mask == BCM_FIELD_EXACT_MATCH_MASK) {
                rv = _bcm_esw_modid_is_local(unit, data, &isLocal);
                BCM_IF_ERROR_RETURN(rv);
                if (isLocal) {
                    rv = bcm_esw_stk_my_modid_get(unit, &data);
                    BCM_IF_ERROR_RETURN(rv);
                }
            } else {
                return (BCM_E_PARAM);
            }
        }
    }

    BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit, entry,
        bcmFieldQualifyDstModid, (uint32 *)&data, (uint32 *)&mask, 0));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstModid,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* Note:
 *    Deprecated in favor of bcm_field_qualify_DstPort().
 */
int
bcm_esw_field_qualify_DstPortTgid(int unit, bcm_field_entry_t entry,
                                  bcm_port_t data, bcm_port_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);
    rv = _field_qualify_PortTgid(unit,entry, bcmFieldQualifyDstPortTgid, 
                                 data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_DstPort(int unit, bcm_field_entry_t entry,
                              bcm_module_t data_modid,
                              bcm_module_t mask_modid,
                              bcm_port_t   data_port,
                              bcm_port_t   mask_port)
{
    _field_control_t *fc;      /* Field control structure. */
    bcm_module_t     mymodid;  /* Local module id.         */
    int              isLocal;  /* Local module id flag.    */
    int              rv;       /* Operation return status. */

    if (BCM_GPORT_IS_SET(data_port)) {
        
       rv = _field_qualifier_gport_resolve(unit, data_port, mask_port, 
                                           &data_port, &data_modid, NULL);
       BCM_IF_ERROR_RETURN(rv);
       mask_modid = BCM_FIELD_EXACT_MATCH_MASK;
    } else {
        if ((NUM_MODID(unit) > 1) && (SOC_IS_TR_VL(unit)) ) {
            if ((data_port < 0) || (data_port > 31)) {
                return (BCM_E_PARAM);
            }
            if ((mask_modid == BCM_FIELD_EXACT_MATCH_MASK) && 
                (mask_port  == BCM_FIELD_EXACT_MATCH_MASK)) {
                rv = _bcm_esw_modid_is_local(unit, data_modid, &isLocal);
                BCM_IF_ERROR_RETURN(rv);
                if (isLocal) {
                    rv = bcm_esw_stk_my_modid_get(unit, &mymodid);
                    BCM_IF_ERROR_RETURN(rv);
                    while (mymodid != data_modid) {
                       data_modid -= 1;
                       data_port += 32;
                    }
                }
            }
        }
    }
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_Port(unit, entry, data_modid, mask_modid,
                             data_port, mask_port, bcmFieldQualifyDstPort);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_DstTrunk(int unit, bcm_field_entry_t entry,
                               bcm_trunk_t data, bcm_trunk_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    if (BCM_GPORT_IS_SET(data)) {
       rv = _field_qualifier_gport_resolve(unit, data, mask, 
                                           NULL, NULL, &data);
       BCM_IF_ERROR_RETURN(rv);
    }
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_Trunk(unit, entry, data, mask,
                                bcmFieldQualifyDstTrunk);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_L4SrcPort(int unit, bcm_field_entry_t entry,
                                bcm_l4_port_t data, bcm_l4_port_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL4SrcPort,
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_L4DstPort(int unit, bcm_field_entry_t entry,
                                bcm_l4_port_t data, bcm_l4_port_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL4DstPort,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerL4SrcPort(int unit, bcm_field_entry_t entry,
                                bcm_l4_port_t data, bcm_l4_port_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerL4SrcPort,
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerL4DstPort(int unit, bcm_field_entry_t entry,
                                bcm_l4_port_t data, bcm_l4_port_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerL4DstPort,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanId
 * Purpose:
 *       Set match criteria for bcmFieildQualifyOuterVlanId
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanId(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t data, 
    bcm_vlan_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyOuterVlanId, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanPri
 * Purpose:
 *       Set match criteria for bcmFieildQualifyOuterVlanPri
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanPri(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyOuterVlanPri, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanCfi
 * Purpose:
 *       Set match criteria for bcmFieildQualifyOuterVlanCfi
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanCfi(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyOuterVlanCfi, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanId
 * Purpose:
 *       Set match criteria for bcmFieildQualifyInnerVlanId
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanId(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t data, 
    bcm_vlan_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerVlanId, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_ForwardingVlanId
 * Purpose:
 *      Set match criteria for bcmFieildQualifyForwardingVlanId
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ForwardingVlanId(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t data, 
    bcm_vlan_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyForwardingVlanId, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_Vpn
 * Purpose:
 *      Set match criteria for bcmFieildQualifyVpn
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Vpn(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vpn_t data, 
    bcm_vpn_t mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyVpn, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanPri
 * Purpose:
 *       Set match criteria for bcmFieildQualifyInnerVlanPri
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanPri(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerVlanPri, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanCfi
 * Purpose:
 *       Set match criteria for bcmFieildQualifyInnerVlanCfi
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanCfi(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerVlanCfi, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanId_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyOuterVlanId
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanId_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint16_get(unit, entry, 
                                            bcmFieldQualifyOuterVlanId,
                                            data, mask);
}


/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanPri_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyOuterVlanPri
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanPri_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyOuterVlanPri,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanCfi_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyOuterVlanCfi_get
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanCfi_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyOuterVlanCfi,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanId_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyInnerVlanId
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanId_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint16_get(unit, entry, 
                                            bcmFieldQualifyInnerVlanId,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_ForwardingVlanId_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyForwardingVlanId
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ForwardingVlanId_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint16_get(unit, entry, 
                                            bcmFieldQualifyForwardingVlanId,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Vpn_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyVpn
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Vpn_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vpn_t *data, 
    bcm_vpn_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint16_get(unit, entry, 
                                            bcmFieldQualifyVpn,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanPri_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyInnerVlanPri
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanPri_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyInnerVlanPri,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanCfi_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyInnerVlanCfi_get
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanCfi_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyInnerVlanCfi,
                                            data, mask);
}



int
bcm_esw_field_qualify_OuterVlan(int unit, bcm_field_entry_t entry,
                                bcm_vlan_t data, bcm_vlan_t mask)
{

    int rv;                          /* Operation return status. */

    rv = bcm_esw_field_qualify_OuterVlanId(unit, entry, 
                                           (data & 0xfff), 
                                           (mask & 0xfff));
    BCM_IF_ERROR_RETURN(rv);

    rv = bcm_esw_field_qualify_OuterVlanCfi(unit, entry, 
                                            ((data >> 12) & 0x1),
                                            ((mask >> 12) & 0x1));
    BCM_IF_ERROR_RETURN(rv);

    rv = bcm_esw_field_qualify_OuterVlanPri(unit, entry,
                                            (data >> 13),
                                            (mask >> 13));
    return (rv);
}

int
bcm_esw_field_qualify_InnerVlan(int unit, bcm_field_entry_t entry,
                                bcm_vlan_t data, bcm_vlan_t mask)
{
    int rv;            /* Operation return status. */

    rv = bcm_esw_field_qualify_InnerVlanId(unit, entry, 
                                           (data & 0xfff), 
                                           (mask & 0xfff));
    BCM_IF_ERROR_RETURN(rv);

    rv = bcm_esw_field_qualify_InnerVlanCfi(unit, entry, 
                                            ((data >> 12) & 0x1),
                                            ((mask >> 12) & 0x1));
    BCM_IF_ERROR_RETURN(rv);

    rv = bcm_esw_field_qualify_InnerVlanPri(unit, entry,
                                            (data >> 13),
                                            (mask >> 13));
    return (rv);
}

int
bcm_esw_field_qualify_EtherType(int unit, bcm_field_entry_t entry,
                                uint16 data, uint16 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyEtherType,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_IpProtocol(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIpProtocol,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_esw_field_qualify_LookupStatus DEPRECATED - might be removed in 
   next SDK release. 
 */
int
bcm_esw_field_qualify_LookupStatus(int unit, bcm_field_entry_t entry,
                                   uint32 data, uint32 mask)
{
    int value;
    const uint32        data_max = (1 << 16) - 1;

    /* Range check data and mask values. */
    if (data > data_max || mask > data_max) {
        FP_ERR(("FP(unit %d) Error: LookupStatus data=%#x or mask=%#x out of range (0-%d).",
                unit, data, mask, data_max));
        return (BCM_E_PARAM);
    }

#ifdef BCM_RAPTOR_SUPPORT
    if (SOC_IS_RAPTOR(unit)) {
        if ((mask & BCM_FIELD_LOOKUP_L3UC_SA_HIT) ||
            (mask & BCM_FIELD_LOOKUP_L3UC_DA_HIT) ||
            (mask & BCM_FIELD_LOOKUP_L3MC_SGV_HIT) ||
            (mask & BCM_FIELD_LOOKUP_L3_LPM_HIT)) {
            return BCM_E_UNAVAIL;
        }
    }
#endif /* BCM_RAPTOR_SUPPORT */

    if (mask & BCM_FIELD_LOOKUP_ING_STP_MASK) {
        switch (data & BCM_FIELD_LOOKUP_ING_STP_MASK) {
          case BCM_FIELD_LOOKUP_ING_STP_DIS:
              value = BCM_STG_STP_DISABLE;
              break;
          case BCM_FIELD_LOOKUP_ING_STP_BLK:
              value = BCM_STG_STP_BLOCK;
              break;
          case BCM_FIELD_LOOKUP_ING_STP_LRN:
              value = BCM_STG_STP_LEARN;
              break;
          case BCM_FIELD_LOOKUP_ING_STP_FWD:
              value = BCM_STG_STP_FORWARD;
              break;
          default:
              return (BCM_E_PARAM);
        }
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_IngressStpState(unit, entry, value, 0x3));
    }

    if (mask & BCM_FIELD_LOOKUP_DOS_ATTACK) {
        value = (data & BCM_FIELD_LOOKUP_DOS_ATTACK) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_DosAttack(unit, entry, value, 0x1));

    }
    if (mask & BCM_FIELD_LOOKUP_L2_MISS) {
        value = (data & BCM_FIELD_LOOKUP_L2_MISS) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_L2StationMove(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_L3_LPM_HIT) {
        value = (data & BCM_FIELD_LOOKUP_L3_LPM_HIT) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_L3DestRouteHit(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_L3MC_SGV_HIT) {
        value = (data & BCM_FIELD_LOOKUP_L3MC_SGV_HIT) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_IpmcStarGroupHit(unit, entry, value, 0x1));
    }

        if (mask & BCM_FIELD_LOOKUP_MY_STATION_HIT) {
        value = (data & BCM_FIELD_LOOKUP_MY_STATION_HIT) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_MyStationHit(unit, entry, value, 0x1));
    }
    if (mask & BCM_FIELD_LOOKUP_L3UC_DA_HIT) {
        value = (data & BCM_FIELD_LOOKUP_L3UC_DA_HIT) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_L3DestHostHit(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_L3UC_SA_HIT) {
        value = (data & BCM_FIELD_LOOKUP_L3UC_SA_HIT) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_L3SrcHostHit(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_L2_CACHE_HIT) {
        value = (data & BCM_FIELD_LOOKUP_L2_CACHE_HIT) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_L2CacheHit(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_L3_ROUTABLE) {
        value = (data & BCM_FIELD_LOOKUP_L3_ROUTABLE) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_L3Routable(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_L2_DA_HIT) {
        value = (data & BCM_FIELD_LOOKUP_L2_DA_HIT) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_L2DestHit(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_L2_SA_HIT) {
        value = (data & BCM_FIELD_LOOKUP_L2_SA_HIT) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_L2SrcHit(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_L2_SA_STATIC) {
        value = (data & BCM_FIELD_LOOKUP_L2_SA_STATIC) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_L2SrcStatic(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_VLAN_VALID) {
        value = (data & BCM_FIELD_LOOKUP_VLAN_VALID) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_ForwardingVlanValid(unit, entry, value, 0x1));
    }

    if (mask & BCM_FIELD_LOOKUP_VXLT_HIT) {
        value = (data & BCM_FIELD_LOOKUP_VXLT_HIT) ? 0x1 : 0x0;
        BCM_IF_ERROR_RETURN
            (bcm_esw_field_qualify_VlanTranslationHit(unit, entry, value, 0x1));
    }

    if ((mask & BCM_FIELD_LOOKUP_L3_TUN_HIT) || 
        (mask & BCM_FIELD_LOOKUP_MPLS_BOS_TERMINATED)) {
#ifdef BCM_TRIUMPH2_SUPPORT /* BCM_TRIUMPH2_SUPPORT */
        if (SOC_IS_TRIUMPH2(unit) || SOC_IS_TD_TT(unit) ||
            SOC_IS_APOLLO(unit) || SOC_IS_VALKYRIE2(unit) ||
            SOC_IS_ENDURO(unit) || SOC_IS_KATANA(unit)) {
            value = (data & BCM_FIELD_LOOKUP_MPLS_BOS_TERMINATED) ? 0x1 : 0x0;
            BCM_IF_ERROR_RETURN
                (bcm_esw_field_qualify_MplsTerminated(unit, entry, value, 0x1));
        } else 
#endif /* !BCM_TRIUMPH2_SUPPORT */
        {
            value = (data & BCM_FIELD_LOOKUP_L3_TUN_HIT) ? 0x1 : 0x0;
            BCM_IF_ERROR_RETURN
                (bcm_esw_field_qualify_TunnelTerminated(unit, entry, value, 0x1));
        }
    }

    return (BCM_E_NONE);
}


/* bcm_field_qualify_DosAttack */
int 
bcm_esw_field_qualify_DosAttack(int unit, bcm_field_entry_t entry, 
                                uint8 data, uint8 mask) 
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDosAttack,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_IpmcStarGroupHit */
int 
bcm_esw_field_qualify_IpmcStarGroupHit(int unit, bcm_field_entry_t entry, 
                                       uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIpmcStarGroupHit,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_MyStationHit */
int 
bcm_esw_field_qualify_MyStationHit(int unit, bcm_field_entry_t entry, 
                                       uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyMyStationHit,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2PayloadFirstEightBytes
 * Purpose:
 *      Add match criteria for bcmFieildQualifyL2PayloadFirstEightBytes
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data1 - (IN) Qualifier first four bytes of matched data.
 *      data2 - (IN) Qualifier last four bytes of matched data.
 *      mask1 - (IN) Qualifier first four bytes of matched mask.
 *      mask2 - (IN) Qualifier last four bytes of matched mask.
 *
 * Note: Values passed in data1 and data2 should be in actual packet data 
 *       format order.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2PayloadFirstEightBytes(int unit,
                                               bcm_field_entry_t entry, 
                                               uint32 data1, uint32 data2,
                                               uint32 mask1, uint32 mask2)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    rv = _field_qualify_L2PayloadFirstEightBytes(unit, entry,
            bcmFieldQualifyL2PayloadFirstEightBytes, data1, data2,
            mask1, mask2);

    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_L3DestRouteHit */
int 
bcm_esw_field_qualify_L3DestRouteHit(int unit, bcm_field_entry_t entry, 
                                     uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL3DestRouteHit,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_L3DestHostHit */
int 
bcm_esw_field_qualify_L3DestHostHit(int unit, bcm_field_entry_t entry, 
                                    uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL3DestHostHit,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_L3SrcHostHit */
int 
bcm_esw_field_qualify_L3SrcHostHit(int unit, bcm_field_entry_t entry, 
                                   uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL3SrcHostHit,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_L2CacheHit */
int 
bcm_esw_field_qualify_L2CacheHit(int unit, bcm_field_entry_t entry, 
                                  uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL2CacheHit,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_L2StationMove */
int 
bcm_esw_field_qualify_L2StationMove(int unit, bcm_field_entry_t entry, 
                                    uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL2StationMove,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_L2DestHit */
int 
bcm_esw_field_qualify_L2DestHit(int unit, bcm_field_entry_t entry, 
                                uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL2DestHit,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_L2SrcStatic */
int 
bcm_esw_field_qualify_L2SrcStatic(int unit, bcm_field_entry_t entry, 
                                  uint8 data, uint8 mask) 
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL2SrcStatic,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_L2SrcHit */
int 
bcm_esw_field_qualify_L2SrcHit(int unit, bcm_field_entry_t entry, 
                               uint8 data, uint8 mask) 
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL2SrcHit,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* bcm_field_qualify_IngressStpState */
int 
bcm_esw_field_qualify_IngressStpState(int unit,bcm_field_entry_t entry, 
                                      uint8 data, uint8 mask) 
{
    _field_control_t *fc;
    int              value;
    int              rv;

    switch (data) {
      case BCM_STG_STP_DISABLE:
          value = 0; 
          break;
      case BCM_STG_STP_BLOCK:
          value = 1; 
          break;
      case BCM_STG_STP_LEARN:
          value = 2; 
          break;
      case BCM_STG_STP_FORWARD:
          value = 3; 
          break;
      default:
          return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIngressStpState,
                            value, 0x3);
    FP_UNLOCK(fc);
    return (rv);
} 

/* bcm_field_qualify_ForwardingVlanValid */
int 
bcm_esw_field_qualify_ForwardingVlanValid(int unit, bcm_field_entry_t entry, 
                                          uint8 data, uint8 mask) 
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyForwardingVlanValid,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcVirtualPortValid
 *      Set match criteria for bcmFieldQualifySrcVirtualPortValid
 *      qualifier in the field entry.
 * Parameters:
 *      unit    -   (IN) Unit number.
 *      entry   -   (IN) BCM field entry id.
 *      data    -   (IN) Qualifier match data.
 *      mask    -   (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcVirtualPortValid(int unit, bcm_field_entry_t entry,
                                          uint8 data, uint8 mask) 
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifySrcVirtualPortValid,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstL3EgressNextHops
 *      Set match criteria for bcmFieldQualifyDstL3EgressNextHops
 *      qualifier in the field entry.
 * Parameters:
 *      unit    -   (IN) Unit number.
 *      entry   -   (IN) BCM field entry id.
 *      data    -   (IN) Match consecutive Next Hop Index values
 *      mask    -   (IN) Next Hop Index mask value
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_esw_field_qualify_DstL3EgressNextHops(int unit,
    bcm_field_entry_t entry,
    uint32 data,
    uint32 mask)
{
    int rv = BCM_E_UNAVAIL;  /* Operation return status. */
#if defined(INCLUDE_L3)
    _field_control_t *fc;
    uint32 max_nexthop_index = 0;

    /* Check if L3 feature is supported on the device */
    if (!soc_feature(unit, soc_feature_l3)) {
        return (rv);
    }

    /*  Make sure module was initialized. */
    if (!BCM_XGS3_L3_INITIALIZED(unit)) {
        return (rv);
    }

    max_nexthop_index = (BCM_XGS3_L3_NH_TBL_SIZE(unit) - 1);

    /* Check if data or mask is greater than possible table index value */
    if ((mask & ~max_nexthop_index) || (data & ~max_nexthop_index)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* set destination type in data and mask */
    BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit,
        entry, bcmFieldQualifyDstL3EgressNextHops, &data, &mask, 0));

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstL3EgressNextHops,
                          data, mask);
    FP_UNLOCK(fc);
#endif
    return (rv);

}

/* bcm_field_qualify_VlanTranslationHit */
int 
bcm_esw_field_qualify_VlanTranslationHit(int unit, bcm_field_entry_t entry, 
                                         uint8 data, uint8 mask) 
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyVlanTranslationHit,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}


int
bcm_esw_field_qualify_IpInfo(int unit, bcm_field_entry_t entry,
                             uint32 data, uint32 mask)   
{
    _field_control_t    *fc;
    int                 rv;
    const uint32        data_max = BCM_FIELD_IP_HDR_OFFSET_ZERO |
                                   BCM_FIELD_IP_HDR_FLAGS_MF |
                                   BCM_FIELD_IP_CHECKSUM_OK;

    /* Range check data and mask values. */
    if (data > data_max || mask > data_max) {
        FP_ERR(("FP(unit %d) Error: IpInfo data=%#x or mask=%#x out of range (0-%d).",
                unit, data, mask, data_max));
        return (BCM_E_PARAM);
    }
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAPTOR_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (SOC_IS_FIREBOLT2(unit) || SOC_IS_RAVEN(unit) || SOC_IS_TRX(unit) || SOC_IS_HAWKEYE(unit)) {
        /* In FB2 More fragments bit replaced with whole packet bit. */
        data = ((data & BCM_FIELD_IP_HDR_OFFSET_ZERO) | 
                (data & BCM_FIELD_IP_CHECKSUM_OK) | 
                (data ^ BCM_FIELD_IP_HDR_FLAGS_MF));
    }
#endif /* BCM_FIREBOLT_SUPPORT || BCM_RAPTOR_SUPPORT || BCM_TRX_SUPPORT */


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIpInfo,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_PacketRes(int unit, bcm_field_entry_t entry,
                                uint32 data, uint32 mask) 
{
    const uint32        data_max = BCM_FIELD_PKT_RES_LAST;
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Range check data and mask values. */
    if (data > data_max) {
        FP_ERR(("FP(unit %d) Error: PacketRes data=%#x out of range (0-%d).", 
                unit, data, data_max));
        return (BCM_E_PARAM);
    }

    /* Translate data #defines to hardware encodings */
    switch (data) {
        case BCM_FIELD_PKT_RES_UNKNOWN:
            data = 0x0;
            break;
        case BCM_FIELD_PKT_RES_CONTROL:
            data = 0x1;
            break;
        case BCM_FIELD_PKT_RES_BPDU:
            data = 0x2;
            break;
        case BCM_FIELD_PKT_RES_L2BC:
            data = 0x3;
            break;
        case BCM_FIELD_PKT_RES_L2UC:
            data = 0x4;
            break;
        case BCM_FIELD_PKT_RES_L2UNKNOWN:
            data = 0x5;
            break;
        case BCM_FIELD_PKT_RES_L3MCUNKNOWN:
#ifdef BCM_RAPTOR_SUPPORT
            if (SOC_IS_RAPTOR(unit)) {
                return BCM_E_UNAVAIL;
            }
#endif /* BCM_RAPTOR_SUPPORT */
            data = 0x6;
            break;
        case BCM_FIELD_PKT_RES_L3MCKNOWN:
#ifdef BCM_RAPTOR_SUPPORT
            if (SOC_IS_RAPTOR(unit)) {
                return BCM_E_UNAVAIL;
            }
#endif /* BCM_RAPTOR_SUPPORT */
            data = 0x7;
            break;
        case BCM_FIELD_PKT_RES_L2MCKNOWN:
            data = 0x8;
            break;
        case BCM_FIELD_PKT_RES_L2MCUNKNOWN:
            data = 0x9;
            break;
        case BCM_FIELD_PKT_RES_L3UCKNOWN:
#ifdef BCM_RAPTOR_SUPPORT
            if (SOC_IS_RAPTOR(unit)) {
                return BCM_E_UNAVAIL;
            }
#endif /* BCM_RAPTOR_SUPPORT */
            data = 0xA;
            break;
        case BCM_FIELD_PKT_RES_L3UCUNKNOWN:
#ifdef BCM_RAPTOR_SUPPORT
            if (SOC_IS_RAPTOR(unit)) {
                return BCM_E_UNAVAIL;
            }
#endif /* BCM_RAPTOR_SUPPORT */
            data = 0xB;
            break;
        case BCM_FIELD_PKT_RES_MPLSKNOWN:
            if (SOC_IS_EASYRIDER(unit) || SOC_IS_TR_VL(unit)) {
                data = 0xC;
                break;
            }
            return (BCM_E_UNAVAIL);
        case BCM_FIELD_PKT_RES_MPLSL3KNOWN:
            if (SOC_IS_EASYRIDER(unit) || SOC_IS_TR_VL(unit)) {
                data = 0xD;
                break;
            }
            return (BCM_E_UNAVAIL);
        case BCM_FIELD_PKT_RES_MPLSL2KNOWN:
            if (SOC_IS_EASYRIDER(unit) || SOC_IS_TR_VL(unit)) {
                data = 0xE;
                break;
            }
            return (BCM_E_UNAVAIL);
        case BCM_FIELD_PKT_RES_MPLSUNKNOWN:
            if (SOC_IS_EASYRIDER(unit) || SOC_IS_TR_VL(unit)) {
                data = 0xF;
                break;
            }
            return (BCM_E_UNAVAIL);
        default:
            FP_ERR(("FP(unit %d) Error: PacketRes data=%#x undefined\n", unit, data));
            return (BCM_E_PARAM);
    }

    if (SOC_IS_EASYRIDER(unit) &&
        soc_feature(unit, soc_feature_field_pkt_res_adj))
    {
        --data;
    }

    FP_LOCK(fc);
    rv = _field_qualify32(unit, entry, bcmFieldQualifyPacketRes,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_SrcIp(int unit, bcm_field_entry_t entry,
                            bcm_ip_t data, bcm_ip_t mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifySrcIp, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_DstIp(int unit, bcm_field_entry_t entry,
                            bcm_ip_t data, bcm_ip_t mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstIp, data, mask);

    FP_UNLOCK(fc);
    return(rv);
}

int
bcm_esw_field_qualify_DSCP(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDSCP, data, mask);

    FP_UNLOCK(fc);
    return(rv);
}

int
bcm_esw_field_qualify_Tos(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyTos, data, mask);

    FP_UNLOCK(fc);
    return(rv);
}

int
bcm_esw_field_qualify_IpFlags(int unit, bcm_field_entry_t entry,
                              uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;
    const uint8      data_max = BCM_FIELD_IPFLAGS_MASK & ~BCM_FIELD_IPFLAGS_RF;


    /* Reserved flag bit (RFC791) is unused. */
    data &= ~BCM_FIELD_IPFLAGS_RF;
    mask &= ~BCM_FIELD_IPFLAGS_RF;

    /* Range check data and mask values. */
    if (data > data_max) {
        FP_ERR(("FP(unit %d) Error: IpFlags data=%#x out of range (0-%d).",
                unit, data, data_max));
        return (BCM_E_PARAM);
    }


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);
    rv = _field_qualify32(unit, entry, bcmFieldQualifyIpFlags,
                          data, mask);
    FP_UNLOCK(fc);
    return(rv);
}

int
bcm_esw_field_qualify_TcpControl(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;
    const uint8      data_max = BCM_FIELD_TCPCONTROL_MASK;

    /* Range check data and mask values. */
    if (data > data_max) {
        FP_ERR(("FP(unit %d) Error: TcpControl data=%#x or mask=%#x out of range (0-%d).",
                unit, data, mask, data_max));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyTcpControl,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_Ttl(int unit, bcm_field_entry_t entry,
                          uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

#if defined(BCM_FIREBOLT2_SUPPORT)
    if (SOC_IS_FIREBOLT2(unit)) {
        rv =  _bcm_field_fb2_qualify_ttl(unit, entry, data, mask);     
    } else 
#endif /* BCM_FIREBOLT2_SUPPORT */
        
#if defined(BCM_RAPTOR_SUPPORT)
    if (SOC_IS_RAVEN(unit) || SOC_IS_HAWKEYE(unit)) {
        rv =  _bcm_field_raven_qualify_ttl(unit, entry, data, mask);     
    } else 
#endif /* BCM_RAPTOR_SUPPORT */
    {
        rv = _field_qualify32(unit, entry, bcmFieldQualifyTtl, data, mask);
    }
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_qualify_RangeCheck
 *
 * Purpose:
 *     Add a field qualification to a filter entry.
 *
 * Parameters:
 *     unit   - BCM device number
 *     entry  - Field entry to operate on
 *     range  - Range ID to add entry
 *     invert -
 *
 * Returns:
 *     BCM_E_XXX 
 */
int
bcm_esw_field_qualify_RangeCheck(int unit, bcm_field_entry_t entry,
                                 bcm_field_range_t range, int invert)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_control_t       *fc;
    _field_range_t         *fr;
    _field_entry_t         *f_ent;
    _field_stage_t         *stage_fc;
    _bcm_field_qual_data_t  data;
    _bcm_field_qual_data_t  mask;
    int                     rv;
    int                     hw_index = -1;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get field entry part that contains qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, bcmFieldQualifyRangeCheck, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return rv;
    }

    if (NULL == f_ent->group) {
        FP_UNLOCK(fc);
        return (BCM_E_INTERNAL);
    }

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, f_ent->group->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Find range hw entry index. */
    for (fr = stage_fc->ranges; fr != NULL; fr = fr->next) {
        if (fr->rid == range) {
            hw_index = fr->hw_index;
            break;
        }
    }
    if (hw_index < 0) {
        FP_UNLOCK(fc);
        return (BCM_E_NOT_FOUND);
    }

#if defined(BCM_TRX_SUPPORT) 
    /* Range checkers is partially overlaid over 
       interface class selector on trx devices. */
    if (SOC_IS_TRX(unit) && (hw_index > _FP_TRX_RANGE_CHECKER_LOWER_MAX)) {
        rv = _bcm_trx_range_checker_selcodes_update(unit, f_ent);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
    }
#endif /* BCM_TRX_SUPPORT */

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, bcmFieldQualifyRangeCheck, &q_offset);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Read qualifier match value and mask. */
    rv = _bcm_field_qual_value_get(unit, q_offset, f_ent, data, mask);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    if (invert < 0) {
        mask[0] &= ~(1 << hw_index);
    } else {
        mask[0] |= (1 << hw_index);

        if (invert) {
            data[0] &= ~(1 << hw_index);
        } else {
            data[0] |= (1 << hw_index);
        }
    }
    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_SrcIp6(int unit, bcm_field_entry_t entry,
                             bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t    *fc;
    int                 rv;


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifySrcIp6, 
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_DstIp6(int unit, bcm_field_entry_t entry,
                             bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifyDstIp6, 
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_SrcIp6High(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifySrcIp6High,
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_DstIp6High(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifyDstIp6High,
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_SrcIp6Low(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifySrcIp6Low,
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_DstIp6Low(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifyDstIp6Low,
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_Ip6NextHeader(int unit, bcm_field_entry_t entry,
                                    uint8 data, uint8 mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIp6NextHeader,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerIp6NextHeader(int unit, bcm_field_entry_t entry,
                                         uint8 data, uint8 mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerIp6NextHeader,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}
int
bcm_esw_field_qualify_InnerIp6TrafficClass(int unit, bcm_field_entry_t entry,
                                      uint8 data, uint8 mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerIp6TrafficClass,
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerIp6FlowLabel(int unit, bcm_field_entry_t entry,
                                   uint32 data, uint32 mask)
{
    const uint32        data_max = (1 << 20) - 1;
    _field_control_t    *fc;
    int                 rv;

    /* Range check data and mask values. */
    if (data > data_max) {
        return (BCM_E_PARAM);
    }
 
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerIp6FlowLabel,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_Ip6TrafficClass(int unit, bcm_field_entry_t entry,
                                      uint8 data, uint8 mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIp6TrafficClass,
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_Ip6FlowLabel(int unit, bcm_field_entry_t entry,
                                   uint32 data, uint32 mask)
{
    const uint32        data_max = (1 << 20) - 1;
    _field_control_t    *fc;
    int                 rv;

    /* Range check data and mask values. */
    if (data > data_max) {
        return (BCM_E_PARAM);
    }
 
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIp6FlowLabel,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_Ip6HopLimit(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIp6HopLimit,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);

}

int
bcm_esw_field_qualify_InnerIp6HopLimit(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerIp6HopLimit,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_SrcMac(int unit, bcm_field_entry_t entry,
                             bcm_mac_t data, bcm_mac_t mask)
{
    _field_control_t         *fc;
    int                      rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_macaddr(unit, entry, bcmFieldQualifySrcMac,
                                data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_DstMac(int unit, bcm_field_entry_t entry,
                             bcm_mac_t data, bcm_mac_t mask)
{
    _field_control_t         *fc;
    int                      rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_macaddr(unit, entry, bcmFieldQualifyDstMac,
                                data, mask);
    FP_UNLOCK(fc);
    return (rv);

}

/*
 * Function:
 *      bcm_esw_field_qualify_Loopback
 * Purpose:
 *      Add loopback field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      data - (IN) Data to qualify with.
 *      mask - (IN) Mask to qualify with.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Loopback(int unit, 
                           bcm_field_entry_t entry, 
                           uint8 data, 
                           uint8 mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyLoopback, 
                          (data ?  0x1 : 0), (mask ? 0x1 : 0));

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_LoopbackType
 * Purpose:
 *      Add loopback type field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      loopback_type - (IN) Loopback type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_LoopbackType(int unit, 
                               bcm_field_entry_t entry, 
                               bcm_field_LoopbackType_t loopback_type)
{
    _field_control_t *fc;   /* Field control structure. */
    int               rv;   /* Operation return status. */
    uint32            data; /* HW data match criteria.  */
    uint32            mask; /* HW data mask.            */

#ifdef BCM_TRIDENT_SUPPORT
    if (SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) {
        switch (loopback_type) {
            case bcmFieldLoopbackTypeMim:
                data = 0xb;
                mask = 0xf;
                break;
            case bcmFieldLoopbackTypeTrillNetwork:
                data = 0xc;
                mask = 0xf;
                break;
            case bcmFieldLoopbackTypeTrillAccess:
                data = 0xd;
                mask = 0xf;
                break;
            default:
                return (BCM_E_PARAM);
        }
    } else
#endif /* BCM_TRIDENT_SUPPORT */
    {
        switch (loopback_type) { 
            case bcmFieldLoopbackTypeAny:
                data = 0x8;
                mask = 0x8;
                break;
            case bcmFieldLoopbackTypeMirror:
                data = 0xe;
                mask = 0xf;
                break;
            case bcmFieldLoopbackTypeWlan:
                data = 0xc;
                mask = 0xf;
                break;
            case bcmFieldLoopbackTypeMim:
                data = 0xb;
                mask = 0xf;
                break;
            case bcmFieldLoopbackTypeRedirect:
                data = 0x9;
                mask = 0xf;
                break;
            default:
                return (BCM_E_PARAM);
        }
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyLoopbackType, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_TunnelType
 * Purpose:
 *      Add tunnel type field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      tunnel_type - (IN) Data to qualify with.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TunnelType(int unit, 
                             bcm_field_entry_t entry, 
                             bcm_field_TunnelType_t tunnel_type)
{
    _field_control_t *fc;   /* Field control structure. */
    int               rv;   /* Operation return status. */
    uint32            data; /* HW data match criteria.  */
    uint32            mask; /* HW data mask.            */

    switch (tunnel_type) { 
      case bcmFieldTunnelTypeAny:
          data = 0x0;
          mask = 0x0;
          break;
      case bcmFieldTunnelTypeIp:
          data = 0x1;
          mask = 0xf;
          break;
      case bcmFieldTunnelTypeMpls:
          data = 0x2;
          mask = 0xf;
          break;
      case bcmFieldTunnelTypeMim:
          data = 0x3;
          mask = 0xf;
          break;
      case bcmFieldTunnelTypeWlanWtpToAc:
          data = 0x4;
          mask = 0xf;
          break;
      case bcmFieldTunnelTypeWlanAcToAc:
          data = 0x5;
          mask = 0xf;
          break;
      case bcmFieldTunnelTypeAutoMulticast:
          data = 0x6;
          mask = 0xf;
          break;
      case bcmFieldTunnelTypeTrill:
          data = 0x7;
          mask = 0xf;
          break;
      default:
          return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyTunnelType, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_DstL3Egress
 * Purpose:
 *     Add a destination egress object field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field Entry id.
 *      if_id - (IN) Egress object id. 
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstL3Egress(int unit, 
                                  bcm_field_entry_t entry, 
                                  bcm_if_t if_id)
{
    int rv = BCM_E_UNAVAIL;   /* Operation return status. */
#if defined(INCLUDE_L3)
    _field_control_t *fc;   /* Field control structure. */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    uint32 flags;           /* L3 forwarding flags      */
    int nh_ecmp_id;         /* Next hop/Ecmp group id.  */

    /* Get next hop id. */
    rv = bcm_xgs3_l3_egress_id_parse(unit, if_id, &flags, &nh_ecmp_id);
    BCM_IF_ERROR_RETURN(rv);

    if (flags & BCM_L3_MULTIPATH) {
        return (BCM_E_UNAVAIL);
    }

    data = nh_ecmp_id;
    mask = (BCM_FIELD_EXACT_MATCH_MASK);

    BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit,
        entry, bcmFieldQualifyDstL3Egress, &data, &mask, 0));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstL3Egress, 
                          data, mask);

    FP_UNLOCK(fc);
#endif /* INCLUDE_L3 */
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_DstMulticastGroup
 * Purpose:
 *     Add a destination multicast group field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field Entry id.
 *      group - (IN) Multicast group id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMulticastGroup(int unit, 
                                        bcm_field_entry_t entry, 
                                        bcm_gport_t group)
{
    _field_control_t *fc;   /* Field control structure. */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    int rv;                 /* Operation return status. */
    uint8 ipmc_grp_type = 0;/* IPMC group type. */

    /* Input parameters check. */
    if (0 == _BCM_MULTICAST_IS_SET(group)) {
        return (BCM_E_PARAM);
    }

    data  = _BCM_MULTICAST_ID_GET(group); 
    mask = (BCM_FIELD_EXACT_MATCH_MASK);

    if (_BCM_MULTICAST_IS_L3(group)) {
        ipmc_grp_type = TRUE;
    } else if ( _BCM_MULTICAST_IS_L2(group)) {
        ipmc_grp_type = FALSE;
    } else {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit, entry,
        bcmFieldQualifyDstMulticastGroup, &data, &mask, ipmc_grp_type));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstMulticastGroup, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMplsGport
 * Purpose:
 *      Add source mpls port field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field Entry id.
 *      mpls_port_id - (IN) Mpls virtual port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMplsGport(int unit, 
                               bcm_field_entry_t entry, 
                               bcm_gport_t mpls_port_id)
{
    _field_control_t *fc;   /* Field control structure. */
    _field_group_t *fg;     /* Field group structure    */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    int rv;                 /* Operation return status. */
    int ingress_entity = 0; /* Ingress entity or source entity */
    int i;

    /* Input parameters check. */
    if (0 == BCM_GPORT_IS_MPLS_PORT(mpls_port_id)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_bcm_field_entry_group_find(unit, entry, &fg));

    /* Get the source virtual port value */
    data  = BCM_GPORT_MPLS_PORT_ID_GET(mpls_port_id); 

    /* Check which configuration of SrcMplsGport is in use */
    for (i = 0; i < _FP_MAX_ENTRY_WIDTH; i++) {
        if (fg->sel_codes[i].ingress_entity_sel ==
                _bcmFieldFwdEntityMplsGport) {
            ingress_entity = 1;
            break;
        }
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    if (ingress_entity) {
        /* Internal qualifier to set SVP valid bit in Fixed field */
        rv = _field_qualify32(unit, entry, _bcmFieldQualifySvpValid, 1, 1);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
    }

    /* Include all bits for Mask value */
    mask = BCM_FIELD_EXACT_MATCH_MASK;

    /* Qualify Mpls Source Virtual Port */
    rv = _field_qualify_source_virtual_port(unit, entry,
            bcmFieldQualifySrcMplsGport, data, mask, ingress_entity);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_DstMplsGport
 * Purpose:
 *      Add destination mpls port field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field Entry id.
 *      mpls_port_id - (IN)  Mpls virtual port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMplsGport(int unit, 
                               bcm_field_entry_t entry, 
                               bcm_gport_t mpls_port_id)
{
    _field_control_t *fc;   /* Field control structure. */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    int rv;                 /* Operation return status. */

    /* Input parameters check. */
    if (0 == BCM_GPORT_IS_MPLS_PORT(mpls_port_id)) {
        return (BCM_E_PARAM);
    }

    data  = BCM_GPORT_MPLS_PORT_ID_GET(mpls_port_id); 
    mask = (BCM_FIELD_EXACT_MATCH_MASK);

    /* Qualify the destination type qualifier */
    BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit,
        entry, bcmFieldQualifyDstMplsGport, &data, &mask, 0));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstMplsGport, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModPortGport
 * Purpose:
 *      Set match criteria for bcmFieildQualifySrcModPortGport
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match gport.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModPortGport(int unit, 
                                      bcm_field_entry_t entry, 
                                      bcm_gport_t port)
{
    _field_control_t *fc;   /* Field control structure. */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    int rv;                 /* Operation return status. */

    /* Input parameters check. */
    if (0 == BCM_GPORT_IS_MODPORT(port)) {
        return (BCM_E_PARAM);
    }

    data  = BCM_GPORT_MODPORT_PORT_GET(port);
    data |= ((BCM_GPORT_MODPORT_MODID_GET(port)) << _FP_PORT_BITWIDTH(unit));
    mask = BCM_FIELD_EXACT_MATCH_MASK;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifySrcModPortGport, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModuleGport
 * Purpose:
 *      Set match criteria for bcmFieildQualifySrcModuleGport
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match gport.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModuleGport(int unit, 
                                      bcm_field_entry_t entry, 
                                      bcm_gport_t port)
{
    _field_control_t *fc;   /* Field control structure. */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    int rv;                 /* Operation return status. */

    /* Input parameters check. */
    if (0 == BCM_GPORT_IS_MODPORT(port)) {
        return (BCM_E_PARAM);
    }

    data = BCM_GPORT_MODPORT_MODID_GET(port);
    mask = BCM_FIELD_EXACT_MATCH_MASK;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifySrcModuleGport, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMimGport
 * Purpose:
 *      Add source mac in mac port field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field Entry id.
 *      mim_port_id - (IN) Mim virtual port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMimGport(int unit, 
                              bcm_field_entry_t entry, 
                              bcm_gport_t mim_port_id)
{
    _field_control_t *fc;   /* Field control structure. */
    _field_group_t *fg;     /* Field group structure    */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    int rv;                 /* Operation return status. */
    int ingress_entity = 0; /* Ingress entity or source entity */
    int i;

    /* Input parameters check. */
    if (0 == BCM_GPORT_IS_MIM_PORT(mim_port_id)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_bcm_field_entry_group_find(unit, entry, &fg));

    /* Get the source virtual port value */
    data  = BCM_GPORT_MIM_PORT_ID_GET(mim_port_id);

    /* Check which configuration of SrcMimGport is in use */
    for (i = 0; i < _FP_MAX_ENTRY_WIDTH; i++) {
        if (fg->sel_codes[i].ingress_entity_sel ==
                _bcmFieldFwdEntityMimGport) {
            ingress_entity = 1;
            break;
        }
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    if (ingress_entity) {
        /* Internal qualifier to set SVP valid bit in Fixed field */
        rv = _field_qualify32(unit, entry, _bcmFieldQualifySvpValid, 1, 1);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
    }
    
    /* Include all bits for Mask value */
    mask = BCM_FIELD_EXACT_MATCH_MASK;

    /* Qualify MiM Source Virtual Port */
    rv = _field_qualify_source_virtual_port(unit, entry,
            bcmFieldQualifySrcMimGport, data, mask, ingress_entity);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_DstMimGport
 * Purpose:
 *      Add destination mac in mac port field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field Entry id.
 *      mim_port_id - (IN) Mim virtual port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMimGport(int unit, 
                              bcm_field_entry_t entry, 
                              bcm_gport_t mim_port_id)
{
    _field_control_t *fc;   /* Field control structure. */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    int rv;                 /* Operation return status. */

    /* Input parameters check. */
    if (0 == BCM_GPORT_IS_MIM_PORT(mim_port_id)) {
        return (BCM_E_PARAM);
    }

    data  = BCM_GPORT_MIM_PORT_ID_GET(mim_port_id); 
    mask = (BCM_FIELD_EXACT_MATCH_MASK);

    BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit,
        entry, bcmFieldQualifyDstMimGport, &data, &mask, 0));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstMimGport, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}



/*
 * Function:
 *      bcm_esw_field_qualify_SrcWlanGport
 * Purpose:
 *      Add source wlan port field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field Entry id.
 *      wlan_port_id - (IN) Wlan virtual port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcWlanGport(int unit, 
                               bcm_field_entry_t entry, 
                               bcm_gport_t wlan_port_id)
{
    _field_control_t *fc;   /* Field control structure. */
    _field_group_t *fg;     /* Field group structure    */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    int rv;                 /* Operation return status. */

    /* Input parameters check. */
    if (0 == BCM_GPORT_IS_WLAN_PORT(wlan_port_id)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_bcm_field_entry_group_find(unit, entry, &fg));

    data  = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
    data |= (1 << 14);
    mask = 0x7fff;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifySrcWlanGport, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}



/*
 * Function:
 *      bcm_esw_field_qualify_DstWlanGport
 * Purpose:
 *      Add destination wlan port field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field Entry id.
 *      wlan_port_id - (IN) Wlan virtual port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstWlanGport(int unit, 
                               bcm_field_entry_t entry, 
                               bcm_gport_t wlan_port_id)
{
    _field_control_t *fc;   /* Field control structure. */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    int rv;                 /* Operation return status. */

    /* Input parameters check. */
    if (0 == BCM_GPORT_IS_WLAN_PORT(wlan_port_id)) {
        return (BCM_E_PARAM);
    }

    data  = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id); 
    mask = (BCM_FIELD_EXACT_MATCH_MASK);

    BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit,
        entry, bcmFieldQualifyDstWlanGport, &data, &mask, 0));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstWlanGport, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_qualify_PacketFormat
 *
 * Purpose:
 *     Add packet format qualification data and mask to an entry.
 *
 * Parameters:
 *     unit            - BCM unit number
 *     entry           - Entry ID
 *     data            - BCM_FIELD_PKT_FMT_xxx values.
 *     mask            - Mask of above values
 * Returns:
 *     BCM_E_INIT      - Unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found in unit.
 *     BCM_E_PARAM     - bad packet format
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_qualify_PacketFormat(int unit, bcm_field_entry_t entry,
                                   uint32 data, uint32 mask)
{
    bcm_field_IpType_t     iptype;         /* QualifyIptype value.    */
    uint8                  data_val;       /* Data portion value.     */
    uint8                  mask_val;       /* Mask portion value.     */
    bcm_field_L2Format_t   l2_fmt;         /* QualifyL2Format value.  */
    _field_entry_t         *f_ent;         /* Field entry structure.  */
    uint32                 type = 0;          
    _field_control_t       *fc;
    int                    rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    data_val = data & BCM_FIELD_PKT_FMT_L2_MASK;
    mask_val = mask & BCM_FIELD_PKT_FMT_L2_MASK;
    data     &= ~BCM_FIELD_PKT_FMT_L2_MASK; 
    mask     &= ~BCM_FIELD_PKT_FMT_L2_MASK; 

    /* Translate #defines for lower 2 bits into HW values. */
    switch (data_val & mask_val) {
      case BCM_FIELD_PKT_FMT_L2_ETH_II:
          if (mask_val) {
              l2_fmt = bcmFieldL2FormatEthII; 
          } else {
              l2_fmt = bcmFieldL2FormatAny; 
          }
          break;
      case BCM_FIELD_PKT_FMT_L2_SNAP:
          l2_fmt  = bcmFieldL2FormatSnap; 
          break;
      case BCM_FIELD_PKT_FMT_L2_LLC:
      case BCM_FIELD_PKT_FMT_L2_802_3:
          l2_fmt  = bcmFieldL2FormatLlc; 
          break;
      default:
          FP_ERR(("FP(unit %d) Error: Invalid l2 format =%d\n", unit,(data_val & mask_val)));
          FP_UNLOCK(fc);
          return (BCM_E_INTERNAL);
    }
    rv = bcm_esw_field_qualify_L2Format(unit, entry, l2_fmt);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    data_val = (data & BCM_FIELD_PKT_FMT_TAGGED_MASK) >> 2;
    mask_val = (mask & BCM_FIELD_PKT_FMT_TAGGED_MASK) >> 2;
    data     &= ~BCM_FIELD_PKT_FMT_TAGGED_MASK; 
    mask     &= ~BCM_FIELD_PKT_FMT_TAGGED_MASK; 
    rv = bcm_esw_field_qualify_VlanFormat(unit, entry, data_val, mask_val);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Split off the IpType portion of the data and mask */
    type = ((data >> 2) & 0xc) | ((mask >> 4) & 0x3);

    switch (type) {                           /* data mask */
        case 0x0:                             /*  00   00  */
        case 0x4:                             /*  01   00  */
        case 0x8:                             /*  10   00  */
        case 0xc:                             /*  11   00  */
            iptype = bcmFieldIpTypeAny;
            break; 
        case 0x1:                             /*  00   01  */
        case 0x9:                             /*  10   01  */
            iptype = bcmFieldIpTypeIpv4Not;
            break; 
        case 0x2:                             /*  00   10  */
        case 0x6:                             /*  01   10  */
            iptype = bcmFieldIpTypeIpv6Not;
            break; 
        case 0x3:                             /*  00   11  */
            iptype = bcmFieldIpTypeNonIp;
            break; 
        case 0x5:                             /*  01   01  */
        case 0x7:                             /*  01   11  */
        case 0xd:                             /*  11   01  */
            iptype = bcmFieldIpTypeIpv4Any;
            break; 
        case 0xa:                             /*  10   10  */
        case 0xb:                             /*  10   11  */
        case 0xe:                             /*  11   10  */
            iptype = bcmFieldIpTypeIpv6;
            break; 
        case 0xf:                             /*  11   11  */
            FP_UNLOCK(fc);
            /* No packet can be both IPv4 & IPv6. */
            FP_ERR(("FP(unit %d) Error: a packet can't be both IPv4 and IPv6.\n",
                    unit));
            return (BCM_E_PARAM);
        default:
            FP_UNLOCK(fc);
            FP_ERR(("FP(unit %d) Error: invalid type=%#x\n", unit, type));
            return (BCM_E_INTERNAL);
    }
    FP_VERB(("FP: type=%#x produced iptype=%s\n", type,
             _field_qual_IpType_name(iptype)));

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (soc_feature(unit, soc_feature_field_multi_stage) && 
        (_BCM_FIELD_STAGE_EGRESS == f_ent->group->stage_id)) {
        if (iptype != bcmFieldIpTypeAny) {
            FP_UNLOCK(fc);
            return (BCM_E_RESOURCE);
        }
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT*/

    if (iptype != bcmFieldIpTypeAny) {
        rv = bcm_esw_field_qualify_IpType(unit, entry, iptype);
    }
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_qualify_SrcMacGroup
 *
 * Purpose:
 *     Add Src MAC group qualification data and mask to an entry.
 *
 * Parameters:
 *     unit            - BCM unit number
 *     entry           - Entry ID
 *     data            - Src MAC Group (a.k.a. MAC Block index)
 *     mask            - mask for the above data
 * Returns:
 *     BCM_E_INIT      - Unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found in unit.
 *     BCM_E_PARAM     - Wrong parameter
 *     BCM_E_NONE      - Success
 * Notes:
 *     Whenever a new chip is added, the src_mac_group_max needs 
 *     to be set properly. See _FIELD_<chip>_SRC_MAC_GROUP_MAX in
 *     include/bcm_int/esw/field.h
 */
int
bcm_esw_field_qualify_SrcMacGroup(int unit, bcm_field_entry_t entry,
                                  uint32 data, uint32 mask)
{
    _field_control_t       *fc;
    int                    rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = bcm_esw_field_qualify_SrcClassL2(unit, entry, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *     bcm_esw_field_qualify_SrcClassL3
 * Purpose:
 *     Add Source L2 Class qualification data and mask to an entry.
 * Parameters:
 *     unit            - (IN) BCM unit number
 *     entry           - (IN) Entry ID
 *     data            - (IN) Source lookup class id. 
 *     mask            - (IN) Source lookup class mask. 
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_SrcClassL3(int unit, bcm_field_entry_t entry,
                                     uint32 data, uint32 mask)
{
    _field_control_t       *fc;
    int                    rv;

    /* Input parameters check. */
    if (data > SOC_ADDR_CLASS_MAX(unit)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifySrcClassL3, 
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *     bcm_esw_field_qualify_SrcClassField
 * Purpose:
 *     Add Source Field Class qualification data and mask to an entry.
 * Parameters:
 *     unit            - (IN) BCM unit number
 *     entry           - (IN) Entry ID
 *     data            - (IN) Source lookup class id. 
 *     mask            - (IN) Source lookup class mask. 
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_SrcClassField(int unit, bcm_field_entry_t entry,
                                    uint32 data, uint32 mask)
{
    _field_control_t       *fc;
    int                    rv;

    /* Input parameters check. */
    if (data > SOC_ADDR_CLASS_MAX(unit)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifySrcClassField, 
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function: 
 *     bcm_esw_field_qualify_SrcClassL2
 * Purpose:
 *     Add Source Lookup Class qualification data and mask to an entry.
 * Parameters:
 *     unit            - (IN) BCM unit number
 *     entry           - (IN) Entry ID
 *     data            - (IN) Source lookup class id. 
 *     mask            - (IN) Source lookup class mask. 
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_SrcClassL2(int unit, bcm_field_entry_t entry,
                                     uint32 data, uint32 mask)
{
    _field_control_t       *fc;
    int                    rv;

    /* Input parameters check. */
    if (data > SOC_ADDR_CLASS_MAX(unit)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifySrcClassL2, 
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function: 
 *     bcm_esw_field_qualify_DstClassL3
 * Purpose:
 *     Add Source L2 Class qualification data and mask to an entry.
 * Parameters:
 *     unit            - (IN) BCM unit number
 *     entry           - (IN) Entry ID
 *     data            - (IN) Source lookup class id. 
 *     mask            - (IN) Source lookup class mask. 
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_DstClassL3(int unit, bcm_field_entry_t entry,
                                     uint32 data, uint32 mask)
{
    _field_control_t       *fc;
    int                    rv;

    /* Input parameters check. */
    if (data > SOC_ADDR_CLASS_MAX(unit)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstClassL3, 
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *     bcm_esw_field_qualify_DstClassField
 * Purpose:
 *     Add Source Field Class qualification data and mask to an entry.
 * Parameters:
 *     unit            - (IN) BCM unit number
 *     entry           - (IN) Entry ID
 *     data            - (IN) Source lookup class id. 
 *     mask            - (IN) Source lookup class mask. 
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_DstClassField(int unit, bcm_field_entry_t entry,
                                    uint32 data, uint32 mask)
{
    _field_control_t       *fc;
    int                    rv;

    /* Input parameters check. */
    if (data > SOC_ADDR_CLASS_MAX(unit)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstClassField, 
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function: 
 *     bcm_esw_field_qualify_DstClassL2
 * Purpose:
 *     Add Source Lookup Class qualification data and mask to an entry.
 * Parameters:
 *     unit            - (IN) BCM unit number
 *     entry           - (IN) Entry ID
 *     data            - (IN) Source lookup class id. 
 *     mask            - (IN) Source lookup class mask. 
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_DstClassL2(int unit, bcm_field_entry_t entry,
                                     uint32 data, uint32 mask)
{
    _field_control_t       *fc;
    int                    rv;

    /* Input parameters check. */
    if (data > SOC_ADDR_CLASS_MAX(unit)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstClassL2, 
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function: bcm_esw_field_qualify_InnerIpType
 *
 * Purpose:
 *     Add qualification data to an entry for IP Type.
 *
 * Parameters:
 *     unit     - BCM unit number
 *     entry    - Entry ID
 *     type     - Ip type
 *
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_InnerIpType(int unit, bcm_field_entry_t entry,
                             bcm_field_IpType_t type)
{

    if (type >= bcmFieldIpTypeCount) {
        return (BCM_E_PARAM);
    }

    return (BCM_E_UNAVAIL);
}

/*
 * Function: bcm_esw_field_qualify_ForwardingType
 *
 * Purpose:
 *     Add qualification data to an entry for IP Type.
 *
 * Parameters:
 *     unit     - (IN) BCM unit number.
 *     entry    - (IN) Entry ID.
 *     type     - (IN) Forwarding type.
 *
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_ForwardingType(int unit, bcm_field_entry_t entry,
                                     bcm_field_ForwardingType_t type)
{
    _field_control_t    *fc;    /* Field control structure.    */
    int                 rv;     /* Operation return structure. */
    uint32              data=0; /* HW qualifier value.         */
    uint32              mask=0; /* HW qualifier mask.          */

    if (type >= bcmFieldForwardingTypeCount) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    switch (type) {
      case bcmFieldForwardingTypeAny:
           data = 0;
           mask = 0;
           break;
      case bcmFieldForwardingTypeL2:
           data = 0;
           mask = 6;
           break;
      case bcmFieldForwardingTypeL2Independent:
           data = 0;
           mask = 7;
           break;
      case bcmFieldForwardingTypeL2Shared:
           data = 1;
           mask = 7;
           break;
      case bcmFieldForwardingTypeL2Vpn:
           data = 2;
           mask = 7;
           break;
      case bcmFieldForwardingTypeL2VpnDirect:
           data = 3;
           mask = 7;
           break;
      case bcmFieldForwardingTypeL3Direct:
           data = 4;
           mask = 7;
           break;
      case bcmFieldForwardingTypeL3:
           data = 5;
           mask = 7;
           break;
      default:
            rv = BCM_E_PARAM;
    }
    rv = _field_qualify32(unit, entry, bcmFieldQualifyForwardingType, 
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_qualify_IpType
 *
 * Purpose:
 *     Add qualification data to an entry for IP Type.
 *
 * Parameters:
 *     unit     - BCM unit number
 *     entry    - Entry ID
 *     type     - Ip type
 *
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_IpType(int unit, bcm_field_entry_t entry,
                             bcm_field_IpType_t type)
{
    _field_entry_t      *f_ent;
    _field_control_t    *fc;
    int                 rv;

    if (type >= bcmFieldIpTypeCount) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }
    rv = fc->functions.fp_qualify_ip_type(unit, f_ent, type);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_qualify_L2Format
 *
 * Purpose:
 *     Add qualification data to an entry for L2 Format.
 *
 * Parameters:
 *     unit     - (IN) BCM unit number.
 *     entry    - (IN) Entry id.
 *     type     - (IN) Ehternet frame type.
 *
 * Returns:
 *     BCM_E_XXX 
 */
int
bcm_esw_field_qualify_L2Format(int unit, bcm_field_entry_t entry,
                               bcm_field_L2Format_t type)
{
    _field_entry_t      *f_ent;  /* Field entry structure.   */
    uint32              data;    /* L2 format encoding.      */
    uint32              mask;    /* L2 format mask.          */
    _field_control_t    *fc;     /* Field control structure. */
    int                 rv;      /* Operation return status. */

    if (type >= bcmFieldL2FormatCount) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    switch (type) {
      case bcmFieldL2FormatAny:
          data = 0x0;
          mask = 0x0;
          break; 
      case bcmFieldL2FormatEthII:
          data = 0x0;
          mask = 0x3;
          break;
      case bcmFieldL2FormatSnap:
          data = 0x1;
          mask = 0x3;
          break;
      case bcmFieldL2FormatLlc:
      case bcmFieldL2Format802dot3:
          data = 0x2;
          mask = 0x3;
          break;
      default:
          FP_UNLOCK(fc);
          FP_ERR(("FP(unit %d) Error: %d not supported\n", unit, type));
          return (BCM_E_UNAVAIL);
    }
    rv = _field_qualify32(unit, entry, bcmFieldQualifyL2Format, data, mask);
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function: bcm_esw_field_qualify_VlanFormat
 *
 * Purpose:
 *     Add qualification data to an entry for Vlan Tag Format.
 *
 * Parameters:
 *     unit     - (IN) BCM unit number.
 *     entry    - (IN) Entry ID.
 *     data     - (IN) Outer & Inner tag presence info.
 *     mask     - (IN) Data mask.
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_VlanFormat(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
    _field_control_t    *fc;     /* Field control structure. */
    int                 rv;      /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_VlanFormat(unit, entry, bcmFieldQualifyVlanFormat,
                                   data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function: bcm_esw_field_qualify_MHOpcode
 *
 * Purpose:
 *     Add qualification data to an entry for mh opcode. 
 *
 * Parameters:
 *     unit     - (IN) BCM unit number.
 *     entry    - (IN) Entry ID.
 *     data     - (IN) Outer & Inner tag presence info.
 *     mask     - (IN) Data mask.
 * Returns:
 *     BCM_E_XXX     
 */
int
bcm_esw_field_qualify_MHOpcode(int unit, bcm_field_entry_t entry,
                               uint8 data, uint8 mask)
{
    _field_control_t    *fc;     /* Field control structure. */
    int                 rv;      /* Operation return status. */

    if (data > BCM_FIELD_MHOPCODE_IPMULTICAST) {
        FP_ERR(("FP(unit %d) Error: data=%d too large.\n", unit, data));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyMHOpcode, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_qualify_UserDefined
 *
 * Purpose:
 *
 * Parameters:
 *     unit     - BCM unit number
 *     entry    - Entry ID
 *     udf_id   - UDF definition ID returned from previous 
 *                call to bcm_field_udf_create().
 *     data     - Data bytes for the indicated udf_id.
 *                Network byte ordered, BCM_FIELD_USER_FIELD_SIZE bytes.
 *     mask     - Mask bytes for the indicated udf_id.
 *                Network byte ordered, BCM_FIELD_USER_FIELD_SIZE bytes.
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_UserDefined(int unit, bcm_field_entry_t entry,
                                  bcm_field_udf_t udf_id,
                                  uint8 data[BCM_FIELD_USER_FIELD_SIZE],
                                  uint8 mask[BCM_FIELD_USER_FIELD_SIZE])
{
    _bcm_field_qual_offset_t *q_offset;     /* Data qualifier offset in tcam. */
    _bcm_field_qual_offset_t q_offset_temp; /* Data qualifier offset in tcam. */
    uint32                   data_word;     /* Data qualifier match key value.*/
    uint32                   mask_word;     /* Data qualifier match key mask. */
    int                      f2_idx;        /* Temporary index.               */
    _field_control_t         *fc;           /* Field control structure.       */
    _field_stage_t           *stage_fc;
    _field_group_t           *fg    = NULL; /* Field entry group structure.   */
    _field_entry_t           *f_ent = NULL; /* Field entry structure.         */
    int                      qid = 0;       /* Data qualifier id.             */
    int                      rv;            /* Operation return status.       */
    int                      idx;


    /* Range check udf_id and confirm non-null pointers */
    if (udf_id >=BCM_FIELD_USER_NUM_UDFS ||
        data == NULL ||
        mask == NULL) {
        FP_ERR(("FP(unit %d) Error: udf_id=%d out-of-range or "
                "data==NULL || mask==NULL\n", unit, udf_id));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    fg = f_ent->group;

    if (!SHR_BITGET(fg->qset.udf_map, udf_id)) { 
        FP_ERR(("FP(unit %d) Error: udf_id %d not in group=%d Qset\n",
                unit, udf_id, fg->gid));
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }


    switch (fc->udf[udf_id].udf_num) {
        case 0:
#if defined(BCM_ENDURO_SUPPORT) || defined(BCM_KATANA_SUPPORT)
            if(SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit) || SOC_IS_KATANA(unit)) {
                if((udf_id == 3) && 
                  !SHR_BITGET(fg->qset.udf_map, 0) && 
                  !SHR_BITGET(fg->qset.udf_map, 2)) {
                    /* qid = UDF1_31_0 */
                    qid = _bcmFieldQualifyData2;
                } else if((udf_id == 1) && 
                  !SHR_BITGET(fg->qset.udf_map, 0) && 
                  !SHR_BITGET(fg->qset.udf_map, 2)) {
                    /* qid = UDF1_95_64 */
                    qid = _bcmFieldQualifyData3;
                } else {
                    /* qid = UDF1_127_0 */
                    qid = _bcmFieldQualifyData0;
                }
            } else
#endif /* BCM_ENDURO_SUPPORT */            
            {
                qid = _bcmFieldQualifyData0;
            }
            break;
        case 1:
            qid = _bcmFieldQualifyData1;
            break;
        default:
            FP_UNLOCK(fc);
            FP_ERR(("FP(unit %d) Error: Unknown UDF\n", unit));
            return (BCM_E_PARAM);
    }


    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qid, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qid, &q_offset);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

#if defined(BCM_ENDURO_SUPPORT) || defined(BCM_KATANA_SUPPORT)
    if((SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit) || SOC_IS_KATANA(unit)) &&
        ((qid == _bcmFieldQualifyData2) || (qid == _bcmFieldQualifyData3))){
        /* UDF1_31_0/UDF1_95_64 is one UDF only */
        f2_idx = 0;
    } else
#endif /* BCM_ENDURO_SUPPORT */
    {
        f2_idx = (stage_fc->data_ctrl->num_elems - 1) - 
                                     fc->udf[udf_id].user_num;
    }

    /*
     * The data/mask pair passed in here is assumed to
     * be pre-formatted by the user as 4-byte user fields.
     * The byte arrays are assumed to be in network byte order.
     */

    sal_memcpy(&q_offset_temp, q_offset, sizeof(_bcm_field_qual_offset_t));

    q_offset_temp.offset += f2_idx * stage_fc->data_ctrl->elem_size * 8;
    q_offset_temp.width = stage_fc->data_ctrl->elem_size * 8;

    data_word = mask_word = 0;
    for (idx = 0; idx < stage_fc->data_ctrl->elem_size; idx++) {
        data_word |= (uint32)data[idx] <<
            ((stage_fc->data_ctrl->elem_size - 1 - idx) * 8);
        mask_word |= (uint32)mask[idx] <<
            ((stage_fc->data_ctrl->elem_size - 1 - idx) * 8);
    }

    /* Program data/mask pair to tcam buffer. */
    rv = _bcm_field_qual_value_set(unit, &q_offset_temp, f_ent, 
                                   &data_word, &mask_word);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *     bcm_field_qualify_Decap
 *
 * Purpose:
 *     Set DECAP qualification data to an entry.
 *
 * Parameters:
 *     unit     - BCM unit number
 *     entry    - Entry ID
 *     decap    - DECAP type to qualify on
 *
 * Returns:
 *     BCM_E_NONE   - Success
 *     BCM_E_PARAM  - invalid decap value
 *
 */
int
bcm_esw_field_qualify_Decap(int unit, bcm_field_entry_t entry,
                            bcm_field_decap_t decap)
{
        return (BCM_E_UNAVAIL);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstHiGig
 * Purpose:
 *      Qualify on HiGig destination packets.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstHiGig(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    _field_control_t *fc;   /* Field control structure. */
    int rv;                 /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstHiGig,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstHiGig_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstHiGig
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstHiGig_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyDstHiGig,
                                            data, mask);
}

/*
 * Function:
 *     bcm_field_qualify_HiGig
 *
 * Purpose:
 *     Set a HiGig packet qualification on an entry.
 *
 * Parameters:
 *     unit     - BCM unit number
 *     entry    - Entry ID
 *     data     - HiGig packet != 0, non-HiGig packet = 0
 *     mask     - don't care = 0
 *
 * Returns:
 *     BCM_E_NONE   - Success
 *     BCM_E_PARAM  - bcmFieldQualifyHiGig not in group's Qset
 *
 */
int
bcm_esw_field_qualify_HiGig(int unit, bcm_field_entry_t entry,
                            uint8 data, uint8 mask)
{
    int rv = BCM_E_UNAVAIL;   /* Operation return status. */
    _field_control_t *fc;     /* Field control structure. */
    _field_entry_t   *f_ent;  /* Field entry structure.   */
    _field_group_t   *fg;     /* Field group structure.   */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    if (SOC_IS_TRX(unit) || SOC_IS_EASYRIDER(unit)) {
        /* In Triumph, Higig is part of FIXED field of TCAM */
        rv = _field_qualify32(unit, entry, bcmFieldQualifyHiGig,
                              data ? 1 : 0, mask ? 1 : 0);
    } else if (SOC_IS_FBX(unit)) {
        rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        if (f_ent->group->stage_id == _BCM_FIELD_STAGE_LOOKUP) {
            /* FB2 Stage Lookup Higig qualifier is part of the F3. */
            rv = _field_qualify32(unit, entry, bcmFieldQualifyHiGig,
                    data ? 1 : 0, mask ? 1 : 0);
        } else {
            /* Confirm that HiGig is in group's Qset. */
            fg = f_ent->group;
            if (0 == BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyHiGig)) {
                FP_UNLOCK(fc);
                FP_ERR(("FP(unit %d) Error: HiGig not in entry=%d Qset.\n", unit));
                return (BCM_E_PARAM);
            }

            /* Add data & mask to entry. */
            f_ent->tcam.higig      = data;
            f_ent->tcam.higig_mask = mask;
        }
    }
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *     bcm_field_qualify_L3IntfGroup
 *
 * Purpose:
 *     Set a L3IntfGroup packet qualification on an entry.
 *
 * Parameters:
 *     unit     - (IN) BCM unit number
 *     entry    - (IN) Entry ID
 *     data     - (IN) L3 interface group to qualify
 *     mask     - (IN) L3 interface group mask to qualify
 *
 * Returns:
 *     BCM_E_NONE   - Success
 *     BCM_E_PARAM  - bcmFieldQualifyL3IntfGroup not in group's Qset
 *
 */
int
bcm_esw_field_qualify_L3IntfGroup(int unit, bcm_field_entry_t entry,
                                  bcm_if_group_t data, bcm_if_group_t mask)
{
    _field_control_t *fc;   /* Field control structure. */
    int rv;                 /* Operation return status. */

    /* Input parameters check. */
    if ((data < 0) || (mask < 0)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = bcm_esw_field_qualify_InterfaceClassL3(unit, entry, 
                                                (uint32)data, (uint32)mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *     bcm_esw_field_qualify_InterfaceClassPort
 *
 * Purpose:
 *     Set a Port interface class id packet qualification on an entry.
 *
 * Parameters:
 *     unit     - (IN) BCM unit number
 *     entry    - (IN) Entry ID
 *     data     - (IN) Interface Class id.
 *     mask     - (IN) Interface Class mask. 
 *
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_InterfaceClassPort(int unit, bcm_field_entry_t entry,
                                         uint32 data, uint32 mask)
{

    _field_control_t *fc;   /* Field control structure. */
    int rv;                 /* Operation return status. */

    /* Validate data/mask  parameter. */
    if (data  > SOC_INTF_CLASS_MAX(unit)) {
        FP_ERR(("FP(unit %d) Error: data=%#x out-of-range\n", unit, data));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInterfaceClassPort,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *     bcm_esw_field_qualify_InterfaceClassL2
 *
 * Purpose:
 *     Set a Port interface class id packet qualification on an entry.
 *
 * Parameters:
 *     unit     - (IN) BCM unit number
 *     entry    - (IN) Entry ID
 *     data     - (IN) Interface Class id.
 *     mask     - (IN) Interface Class mask. 
 *
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_InterfaceClassL2(int unit, bcm_field_entry_t entry,
                                         uint32 data, uint32 mask)
{
    _field_control_t *fc;   /* Field control structure. */
    int rv;                 /* Operation return status. */

    /* Validate data/mask  parameter. */
    if (data  > SOC_INTF_CLASS_MAX(unit)) {
        FP_ERR(("FP(unit %d) Error: data=%#x out-of-range\n", unit, data));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInterfaceClassL2,
                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *     bcm_esw_field_qualify_InterfaceClassL3
 *
 * Purpose:
 *     Set a L3 interface class id packet qualification on an entry.
 *
 * Parameters:
 *     unit     - (IN) BCM unit number
 *     entry    - (IN) Entry ID
 *     data     - (IN) Interface Class id.
 *     mask     - (IN) Interface Class mask. 
 *
 * Returns:
 *     BCM_E_XXX
 */
int
bcm_esw_field_qualify_InterfaceClassL3(int unit, bcm_field_entry_t entry,
                                       uint32 data, uint32 mask)
{
    _field_control_t *fc;   /* Field control structure. */
    int rv;                 /* Operation return status. */

    /* Validate data/mask  parameter. */
    if (data  > SOC_INTF_CLASS_MAX(unit)) {
        FP_ERR(("FP(unit %d) Error: data=%#x out-of-range\n", unit, data));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInterfaceClassL3,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_qualify_Stage
 *
 * Purpose:
 *
 * Parameters:
 *
 * Returns:
 *     BCM_E_NONE   - Success
 *     BCM_E_PARAM  - bcmFieldQualifyStage not in group's Qset
 */
int
bcm_esw_field_qualify_Stage(int unit, bcm_field_entry_t entry,
                            bcm_field_stage_t stage)
{

#ifdef BCM_EASYRIDER_SUPPORT
    _field_control_t *fc;   /* Field control structure. */
    int      rv;            /* Operation return status. */
    uint8    data;

    if (SOC_IS_EASYRIDER(unit)) {
        switch (stage) {
          case bcmFieldStageFirst:
          case bcmFieldStageIngressEarly:
          case bcmFieldStageDefault:
              data = 0;
              break;
          case bcmFieldStageIngressLate:
          case bcmFieldStageLast:
              data = 1;
              break;
          default:
              FP_ERR(("FP(unit %d) Error: unsupported stage=%d\n", unit, stage));
              return (BCM_E_PARAM);
        }
        BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
        FP_LOCK(fc);
        rv = _field_qualify32(unit, entry, bcmFieldQualifyStage, data, 1);
        FP_UNLOCK(fc);
        return (rv);
    }
#endif /*BCM_EASYRIDER_SUPPORT*/

#ifdef BCM_FIREBOLT_SUPPORT
    if (SOC_IS_FBX(unit)) {
        switch (stage) {
          case bcmFieldStageFirst:
          case bcmFieldStageIngressEarly:
          case bcmFieldStageLast:
          case bcmFieldStageDefault:
              return (BCM_E_NONE);
          case bcmFieldStageIngressLate:
              return (BCM_E_PARAM);
          default:
              return (BCM_E_PARAM);
        }
    }
#endif /*BCM_FIREBOLT_SUPPORT*/
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_SrcIpEqualDstIp(int unit, bcm_field_entry_t entry,
                            uint32 flag)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_EqualL4Port(int unit, bcm_field_entry_t entry,
                            uint32 flag)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_TcpSequenceZero(int unit, bcm_field_entry_t entry,
                            uint32 flag)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_TcpHeaderSize(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

/* Function: 
 *       bcm_field_qualify_InnerIpProtocolCommon
 * Description:
 *       Qualify common L3 protocol ID.
 * Parameters: 
 *   unit     (IN) BCM device number
 *   entry    (IN) Field entry to qualify
 *   protocol (IN) Protocol name to qualify
 * Returns: 
 *   BCM_E_XXX
 */
int
bcm_esw_field_qualify_InnerIpProtocolCommon(int unit, bcm_field_entry_t entry,
                                       bcm_field_IpProtocolCommon_t protocol)
{
    _field_control_t *fc;   /* Field control structure. */
    int      rv;            /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_IpProtocolCommon(unit, entry, 
                                         bcmFieldQualifyInnerIpProtocolCommon, 
                                         protocol);
    FP_UNLOCK(fc);
    return (rv);
}


/* Function: 
 *           bcm_field_qualify_IpProtocolCommon
 * Description: 
 *           Qualify common L3 protocol ID
 * Parameters: 
 *   unit     (IN) BCM device number
 *   entry    (IN) Field entry to qualify
 *   protocol (IN) Protocol name to qualify
 * Returns: 
 *   BCM_E_XXX
 */
int
bcm_esw_field_qualify_IpProtocolCommon(int unit, bcm_field_entry_t entry,
                                       bcm_field_IpProtocolCommon_t protocol)
{
    _field_control_t *fc;   /* Field control structure. */
    int      rv;            /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_IpProtocolCommon(unit, entry, bcmFieldQualifyIpProtocolCommon, protocol);

    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_field_qualify_Snap
 * Description : qualify SNAP headers.
 * Parameters  : (IN) unit     BCM device number
 *               (IN) entry    Field entry to qualify
 *               (IN) data     SNAP fields to qualify
 *               (IN) mask     SNAP mask to qualify
 * Returns     : BCM_E_XXX
 */
int
bcm_esw_field_qualify_Snap(int unit, bcm_field_entry_t entry,
                           bcm_field_snap_header_t data, 
                           bcm_field_snap_header_t mask)
{
    _field_entry_t           *f_ent;
    _bcm_field_qual_offset_t *q_offset;
    uint32                   ref_data[_FP_QUAL_DATA_WORDS];
    uint32                   ref_mask[_FP_QUAL_DATA_WORDS];
    _field_control_t         *fc;
    int                      rv; 


    ref_data[1] = (data.org_code & 0x00ff0000) >> 16;
    ref_data[0] = (data.org_code & 0x0000ffff) << 16 | data.type;

    ref_mask[1] = (mask.org_code & 0x00ff0000) >> 16;
    ref_mask[0] = (mask.org_code & 0x0000ffff) << 16 | mask.type;


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, bcmFieldQualifySnap, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, bcmFieldQualifySnap, &q_offset);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Program data/mask pair to tcam buffer. */
    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, 
                                   ref_data, ref_mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_field_qualify_Llc
 * Description : qualify LLC headers.
 * Parameters  : (IN) unit     BCM device number
 *               (IN) entry    Field entry to qualify
 *               (IN) data     LLC fields to qualify
 *               (IN) mask     LLC mask to qualify
 * Returns     : BCM_E_XXX
 */
int
bcm_esw_field_qualify_Llc(int unit, bcm_field_entry_t entry,
                          bcm_field_llc_header_t data, 
                          bcm_field_llc_header_t mask)
{
    uint32              ref_data;
    uint32              ref_mask;
    _field_control_t    *fc;
    int                 rv; 

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    ref_data = (data.dsap << 16) | (data.ssap << 8) | \
               data.control; 
    ref_mask = (mask.dsap << 16) | (mask.ssap << 8) | \
               mask.control; 
    rv = _field_qualify32(unit, entry, bcmFieldQualifyLlc,
                          ref_data, ref_mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_field_qualify_InnerTpid
 * Description : qualify outer/inner Tpid
 * Parameters  : (IN) unit   BCM driver unit
 *               (IN) entry  Field entry to qualify
 *               (IN) tpid   TPID to qualify
 * Returns     : BCM_E_XXX
 */
int
bcm_esw_field_qualify_InnerTpid(int unit, bcm_field_entry_t entry,
                                uint16 tpid)
{
    int     rv = BCM_E_UNAVAIL; 
#if defined(BCM_FIREBOLT2_SUPPORT) || defined (BCM_TRX_SUPPORT)
    _field_control_t  *fc;
    uint32  mask;
    uint32  data;

    if (SOC_IS_FIREBOLT2(unit) || SOC_IS_TRX(unit)) {
        BCM_IF_ERROR_RETURN(_bcm_field_tpid_hw_encode(unit, tpid, &data));
        mask = 0x03;
        BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
        FP_LOCK(fc);
        rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerTpid, data, mask);
        FP_UNLOCK(fc);
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    return (rv);
}

/* Function    : bcm_field_qualify_OuterTpid
 * Description : qualify outer Tpid
 * Parameters  : (IN) unit   BCM driver unit
 *               (IN) entry  Field entry to qualify
 *               (IN) tpid   TPID to qualify
 * Returns     : BCM_E_XXX
 */
int
bcm_esw_field_qualify_OuterTpid(int unit, bcm_field_entry_t entry,
                                uint16 tpid)
{
    int     rv = BCM_E_UNAVAIL; 
#if defined(BCM_FIREBOLT2_SUPPORT) || defined (BCM_TRX_SUPPORT)
    _field_control_t  *fc;
    uint32  mask;
    uint32  data;

    if (SOC_IS_FIREBOLT2(unit) || SOC_IS_TRX(unit)) {
        BCM_IF_ERROR_RETURN(_bcm_field_tpid_hw_encode(unit, tpid, &data));
        mask = 0x03;
        BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
        FP_LOCK(fc);
        rv = _field_qualify32(unit, entry, bcmFieldQualifyOuterTpid, data, mask);
        FP_UNLOCK(fc);
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
    return (rv);
}


/* Function    : bcm_field_qualify_PortClass
 * Description : qualify on port class.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   Port class to qualify
 *               (IN) mask   Port class mask
 * Returns     : BCM_E_XXX
 */
int
bcm_esw_field_qualify_PortClass(int unit, bcm_field_entry_t entry,
                                uint32 data, uint32 mask)
{
    _field_control_t  *fc;
    int rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = bcm_esw_field_qualify_InterfaceClassPort(unit, entry, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_esw_field_qualify_L3Routable
 * Description : qualify on the L3 Routable bit.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   Single bit
 *               (IN) mask   Single bit mask
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_L3Routable(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL3Routable, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_esw_field_qualify_IpFrag
 * Description : qualify on Ip Frag Info.
 * Parameters  : (IN) unit       BCM device number
 *               (IN) entry      Field entry to qualify
 *               (IN) frag_info  bcm_field_IpFrag_t to qualify
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_IpFrag(int unit, bcm_field_entry_t entry,
                                  bcm_field_IpFrag_t frag_info)
{
    int             rv = BCM_E_UNAVAIL;
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) \
    || defined(BCM_RAPTOR_SUPPORT)
    _field_control_t *fc;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    if (SOC_IS_FIREBOLT2(unit) || SOC_IS_TRX(unit) || 
        SOC_IS_RAVEN(unit) || SOC_IS_HAWKEYE(unit)) {
        rv = _field_qualify_IpFrag(unit, entry, bcmFieldQualifyIpFrag, frag_info);
    }
    FP_UNLOCK(fc);
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT || BCM_RAPTOR_SUPPORT */
    return (rv);
}

/* Function    : bcm_esw_field_qualify_LookupClass0
 * Description : qualify on the Lookup Class 0 coming fronm the output of VFP.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   Class id. 
 *               (IN) mask   Class mask.
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_LookupClass0(int unit, bcm_field_entry_t entry,
                                       uint32 data, uint32 mask)
{
    return  bcm_esw_field_qualify_DstClassField(unit, entry, data, mask);
}

/* Function    : bcm_esw_field_qualify_Vrf
 * Description : qualify on the VRF id.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   Vrf id. 
 *               (IN) mask   Vrf mask.
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_Vrf(int unit, bcm_field_entry_t entry,
                              uint32 data, uint32 mask)
{
    _field_control_t *fc;
    int rv = BCM_E_UNAVAIL;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyVrf, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_esw_field_qualify_L3Ingress
 * Description : qualify on the L3 ingress interface.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   L3 ingress id. 
 *               (IN) mask   L3 ingress mask.
 * Returns     : BCM_E_XXX
 */

int bcm_esw_field_qualify_L3Ingress(int unit, bcm_field_entry_t entry,
    uint32 data, uint32 mask)
{
    _field_control_t *fc;
    int rv = BCM_E_UNAVAIL;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyL3Ingress, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_esw_field_qualify_L4Ports
 * Description : qualify on the 4 bytes after L3 header.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   0/1 4 bytes after L3 header are present. 
 *               (IN) mask   data mask.
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_L4Ports(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv = BCM_E_UNAVAIL;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

#if defined(BCM_TRX_SUPPORT)
    if (SOC_IS_TRX(unit)) {
        rv = _field_qualify32(unit, entry, bcmFieldQualifyL4Ports, data, mask);
    }
#endif  /* BCM_TRX_SUPPORT */
    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_esw_field_qualify_MirrorCopy
 * Description : qualify on the mirrored packets only.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   0/1 Not Mirrored/Mirrored packets. 
 *               (IN) mask   data mask.
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_MirrorCopy(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv = BCM_E_UNAVAIL;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyMirrorCopy, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/* Function    : bcm_esw_field_qualify_TunnelTerminated
 * Description : qualify on the tunnel terminated packets only.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   0/1 Not Tunneled/Tunnel Terminated packets. 
 *               (IN) mask   data mask.
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_TunnelTerminated(int unit, bcm_field_entry_t entry,
                                           uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv = BCM_E_UNAVAIL;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyTunnelTerminated,
                            data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_esw_field_qualify_MplsTerminated
 * Description : qualify on the mpls terminated packets only.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   0/1 Not mpls terminated/mpls Terminated packets. 
 *               (IN) mask   data mask.
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_MplsTerminated(int unit, bcm_field_entry_t entry,
                                           uint8 data, uint8 mask)
{
    _field_control_t *fc;   /* Field control structure. */
    int rv = BCM_E_UNAVAIL; /* Operation return status  */
#if defined(BCM_TRIUMPH2_SUPPORT) /* BCM_TRIUMPH2_SUPPORT */
    _field_group_t *fg;     /* Field group structure    */
    int i;
#endif /* !BCM_TRIUMPH2_SUPPORT */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);
#if defined(BCM_TRIUMPH_SUPPORT)
    if (SOC_IS_TR_VL(unit)) {
#if defined(BCM_TRIUMPH2_SUPPORT) /* BCM_TRIUMPH2_SUPPORT */
        if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit)
            || SOC_IS_VALKYRIE2(unit)) {
            BCM_IF_ERROR_RETURN(_bcm_field_entry_group_find(unit, entry, &fg));
            for (i = 0; i < _FP_MAX_ENTRY_WIDTH; i++) {
                if (fg->sel_codes[i].loopback_type_sel 
                        == (int8) bcmFieldTunnelTypeMpls) {
                    if (1 == data && 1 == mask) {
                        data = (uint8) bcmFieldTunnelTypeMpls;
                        mask = (BCM_FIELD_EXACT_MATCH_MASK);
                    }
                    break;
                }
            }
        }
#endif /* !BCM_TRIUMPH2_SUPPORT */
        rv = _field_qualify32(unit, entry, bcmFieldQualifyMplsTerminated,
                              data, mask);
    }
#endif  /* BCM_TRIUMPH_SUPPORT*/
    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_esw_field_qualify_ExtensionHeaderType
 * Description : Qualify on Next Header Field in First Extension Header.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   Extension Header - Next Header byte.
 *               (IN) mask   Next Header byte mask.
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_ExtensionHeaderType(int unit, 
                                              bcm_field_entry_t entry,
                                              uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv = BCM_E_UNAVAIL;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

#if defined (BCM_TRX_SUPPORT)
    if (SOC_IS_TRX(unit)) {
        rv = _field_qualify32(unit, entry, bcmFieldQualifyExtensionHeaderType,
                              data, mask);
    }
#endif 
    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_esw_field_qualify_ExtensionHeaderSubCode
 * Description : Qualify on First byte after extentsion header length field.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   Extension Header byte after header length field.
 *               (IN) mask   Byte mask.
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_ExtensionHeaderSubCode(int unit, 
                                                 bcm_field_entry_t entry,
                                                 uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv = BCM_E_UNAVAIL;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

#if defined (BCM_TRX_SUPPORT)
    if (SOC_IS_TRX(unit)) {
        rv =  _field_qualify32(unit, entry,
                               bcmFieldQualifyExtensionHeaderSubCode,
                               data, mask);
    }
#endif 
    FP_UNLOCK(fc);
    return (rv);
}

/* Function    : bcm_esw_field_qualify_ExtensionHeader2Type
 * Description : Qualify on Next Header Field in Second Extension Header.
 * Parameters  : (IN) unit   BCM device number
 *               (IN) entry  Field entry to qualify
 *               (IN) data   Extension Header - Next Header byte.
 *               (IN) mask   Next Header byte mask.
 * Returns     : BCM_E_XXX
 */
int bcm_esw_field_qualify_ExtensionHeader2Type(int unit, 
                                              bcm_field_entry_t entry,
                                              uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv = BCM_E_UNAVAIL;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

#if defined (BCM_TRIDENT_SUPPORT)
    if (SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) {
        rv = _field_qualify32(unit, entry, bcmFieldQualifyExtensionHeader2Type,
                              data, mask);
    }
#endif  /* BCM_TRIDENT_SUPPORT */

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerSrcIp(int unit, bcm_field_entry_t entry,
                            bcm_ip_t data, bcm_ip_t mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerSrcIp, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerDstIp(int unit, bcm_field_entry_t entry,
                            bcm_ip_t data, bcm_ip_t mask)
{
    _field_control_t *fc;
    int rv; 

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerDstIp, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerSrcIp6(int unit, bcm_field_entry_t entry,
                             bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t *fc;
    int rv; 

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifyInnerSrcIp6, 
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerDstIp6(int unit, bcm_field_entry_t entry,
                             bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t *fc;
    int rv; 

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifyInnerDstIp6, 
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerSrcIp6High(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifyInnerSrcIp6High,
                            data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerDstIp6High(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    _field_control_t    *fc;
    int                 rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_ip6(unit, entry, bcmFieldQualifyInnerDstIp6High,
                                data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerTos(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv; 

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerTos, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerDSCP(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv; 

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerDSCP, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int
bcm_esw_field_qualify_InnerIpProtocol(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv; 

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerIpProtocol, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

int bcm_esw_field_qualify_InnerIpFrag(int unit, bcm_field_entry_t entry,
                                  bcm_field_IpFrag_t frag_info)
{
    int             rv = BCM_E_UNAVAIL;
#if  defined(BCM_TRX_SUPPORT) 
    _field_control_t *fc;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    if (SOC_IS_TRX(unit)) {
        rv = _field_qualify_IpFrag(unit, entry, 
                                   bcmFieldQualifyInnerIpFrag,
                                   frag_info);
    }
    FP_UNLOCK(fc);
#endif /* BCM_TRX_SUPPORT */
    return (rv);
}

int
bcm_esw_field_qualify_InnerTtl(int unit, bcm_field_entry_t entry,
                          uint8 data, uint8 mask)
{
    _field_control_t *fc;
    int rv; 

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyInnerTtl, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_TranslatedVlanFormat
 * Purpose:
 *      Set match criteria for bcmFieildQualifyTranslatedVlanFormat
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TranslatedVlanFormat( int unit, bcm_field_entry_t entry, 
                                           uint8 data, uint8 mask)
{
    _field_control_t    *fc;     /* Field control structure. */
    int                 rv;      /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_VlanFormat(unit, entry,
                                   bcmFieldQualifyTranslatedVlanFormat,
                                   data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IntPriority
 * Purpose:
 *      Set match criteria for bcmFieildQualifyIntPriority
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IntPriority(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    _field_control_t *fc;
    int rv; 

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIntPriority, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_qualify_Color
 * Purpose:
 *      Set match criteria for bcmFieildQualifyColor
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      color - (IN) Qualifier match color.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Color(int unit, bcm_field_entry_t entry, 
                            uint8 color)
{
    _field_control_t *fc; /* Field control structure. */
    uint8 data;           /* Qualifier data.          */
    int rv;               /* Operation return status. */
    uint8 mask = 0x3;     /* Qualifier mask.          */

    switch (color) {
      case BCM_FIELD_COLOR_GREEN:
          data = 0;
          break;
      case BCM_FIELD_COLOR_RED:
          data = 1;
          break;
      case BCM_FIELD_COLOR_YELLOW:
          data = 3;
          break;
      default:
          return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyColor, data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_FibreChanOuter
 * Purpose:
 *      Add Fibre Channel outer header type field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      fibre_chan_type - (IN) Data to qualify with.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FibreChanOuter(int unit, 
                             bcm_field_entry_t entry, 
                             bcm_field_FibreChan_t fibre_chan_type)
{
    _field_control_t *fc;   /* Field control structure. */
    int               rv;   /* Operation return status. */
    uint32            data; /* HW data match criteria.  */
    uint32            mask; /* HW data mask.            */

    switch (fibre_chan_type) { 
      case bcmFieldFibreChanAny:
          data = 0x0;
          mask = 0x0;
          break;
      case bcmFieldFibreChan:
          data = 0x1;
          mask = 0x7;
          break;
      case bcmFieldFibreChanEncap:
          data = 0x3;
          mask = 0x7;
          break;
      case bcmFieldFibreChanVirtual:
          data = 0x2;
          mask = 0x7;
          break;
      case bcmFieldFibreChanRouted:
          data = 0x4;
          mask = 0x7;
          break;
      default:
          return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyFibreChanOuter, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_FibreChanInner
 * Purpose:
 *      Add Fibre Channel inner header type field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      fibre_chan_type - (IN) Data to qualify with.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FibreChanInner(int unit, 
                             bcm_field_entry_t entry, 
                             bcm_field_FibreChan_t fibre_chan_type)
{
    _field_control_t *fc;   /* Field control structure. */
    int               rv;   /* Operation return status. */
    uint32            data; /* HW data match criteria.  */
    uint32            mask; /* HW data mask.            */

    switch (fibre_chan_type) { 
      case bcmFieldFibreChanAny:
          data = 0x0;
          mask = 0x0;
          break;
      case bcmFieldFibreChan:
          data = 0x1;
          mask = 0x7;
          break;
      case bcmFieldFibreChanEncap:
          data = 0x3;
          mask = 0x7;
          break;
      case bcmFieldFibreChanVirtual:
          data = 0x2;
          mask = 0x7;
          break;
      case bcmFieldFibreChanRouted:
          data = 0x4;
          mask = 0x7;
          break;
      default:
          return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyFibreChanInner, 
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

STATIC int
_bcm_esw_field_qualify_aux_tag(int                 unit,
                               bcm_field_entry_t   entry,
                               bcm_field_qualify_t qual,
                               uint32              data,
                               uint32              mask
                               )
{
    _field_entry_t           *f_ent;
    _bcm_field_qual_offset_t *q_offset;
    uint32                   ref_data[_FP_QUAL_DATA_WORDS];
    uint32                   ref_mask[_FP_QUAL_DATA_WORDS];
    _field_control_t         *fc;
    int                      rv; 

    /* Take the given 32-bit data and mask value, and prefix them with
       a 1 bit, which in the hardware is the "tag valid" bit.
    */ 

    ref_data[1] = 1;
    ref_data[0] = data;

    ref_mask[1] = 1;
    ref_mask[0] = mask;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qual, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qual, &q_offset);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Program data/mask pair to tcam buffer. */
    rv = _bcm_field_qual_value_set(unit, q_offset, f_ent, 
                                   ref_data, ref_mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_VnTag
 * Purpose:
 *      Add NIV VN tag field qualification to a field entry.
 * Parameters:
 *      unit  - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      data  - (IN) Qualifier match data.
 *      mask  - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_esw_field_qualify_VnTag(int unit, bcm_field_entry_t entry,
                            uint32 data, uint32 mask)
{
    return (_bcm_esw_field_qualify_aux_tag(unit,
                                           entry,
                                           bcmFieldQualifyVnTag,
                                           data,
                                           mask
                                           )
            );
}

/*
 * Function:
 *      bcm_esw_field_qualify_CnTag
 * Purpose:
 *      Add CN tag field qualification to a field entry.
 * Parameters:
 *      unit  - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      data  - (IN) Qualifier match data.
 *      mask  - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_esw_field_qualify_CnTag(int unit, bcm_field_entry_t entry,
                            uint32 data, uint32 mask)
{
    return (_bcm_esw_field_qualify_aux_tag(unit,
                                           entry,
                                           bcmFieldQualifyCnTag,
                                           data,
                                           mask
                                           )
            );
}

/*
 * Function:
 *      bcm_esw_field_qualify_FabricQueueTag
 * Purpose:
 *      Add Fabric Queue tag field qualification to a field entry.
 * Parameters:
 *      unit  - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      data  - (IN) Qualifier match data.
 *      mask  - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_esw_field_qualify_FabricQueueTag(int unit, bcm_field_entry_t entry,
                                     uint32 data, uint32 mask)
{
    return (_bcm_esw_field_qualify_aux_tag(unit,
                                           entry,
                                           bcmFieldQualifyFabricQueueTag,
                                           data,
                                           mask
                                           )
            );
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpAuth
 * Purpose:
 *      Set match criteria for bcmFieildQualifyIpAuth
 *                     qualifier to the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */

int 
bcm_esw_field_qualify_IpAuth(int unit, bcm_field_entry_t entry,
                 uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

/*
 * Function:
 *      bcm_esw_field_qualify_BigIcmpCheck
 * Purpose:
 *      Set match criteria for bcmFieildQualifyBigIcmpCheck
 *                     qualifier to the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_BigIcmpCheck(int unit, bcm_field_entry_t entry,
                                         uint32 flag, uint32 size)
{
    return (BCM_E_UNAVAIL);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IcmpTypeCode
 * Purpose:
 *      Set match criteria for bcmFieildQualifyIcmpTypeCode
 *                     qualifier to the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IcmpTypeCode(int unit, bcm_field_entry_t entry,
                                         uint16 data,uint16 mask)
{
    _field_control_t *fc;      /* Field control structure. */
    int              rv;       /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyIcmpTypeCode,
                          data, mask);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IgmpTypeMaxRespTime
 * Purpose:
 *      Set match criteria for bcmFieildQualifyIgmpTypeMaxRespTime
 *                     qualifier to the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IgmpTypeMaxRespTime(int unit, bcm_field_entry_t entry,
                                         uint16 data,uint16 mask)
{
    return (BCM_E_UNAVAIL);
}
/*
 * Function:
 *      bcm_esw_field_qualify_FlowId
 * Purpose:
 *      Set match criteria for bcmFieildQualifyFlowId
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */

int 
bcm_esw_field_qualify_FlowId(int unit, bcm_field_entry_t entry,
                 uint16 data, uint16 mask)
{
    return BCM_E_UNAVAIL; 
}
/*
 * Function:
 *      bcm_esw_field_qualify_InVPort
 * Purpose:
 *      Set match criteria for bcmFieildQualifyInVPort
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */

int 
bcm_esw_field_qualify_InVPort(int unit, bcm_field_entry_t entry,
                 uint8 data, uint8 mask)
{
    return BCM_E_UNAVAIL; 
}
/*
 * Function:
 *      bcm_esw_field_qualify_OutVPort
 * Purpose:
 *      Set match criteria for bcmFieildQualifyOutVPort
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */

int 
bcm_esw_field_qualify_OutVPort(int unit, bcm_field_entry_t entry,
                 uint8 data, uint8 mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_FlowId_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyFlowId
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FlowId_get(int unit, bcm_field_entry_t entry,
                 uint16 *data, uint16 *mask)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_qualify_InVPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInVPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InVPort_get(int unit, bcm_field_entry_t entry,
                 uint8 *data, uint8 *mask)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_qualify_OutVPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOutVPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OutVPort_get(int unit, bcm_field_entry_t entry,
                 uint8 *data, uint8 *mask)
{
    return BCM_E_UNAVAIL;
}

/*  Section: Field Actions  */

/*
 * Function: bcm_esw_field_action_add
 *
 * Purpose:
 *     Add action performed when entry rule is matched for a packet
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - entry ID
 *     action - Action to perform (bcmFieldActionXXX)
 *     param0 - Action parameter (use 0 if not required)
 *     param1 - Action parameter (use 0 if not required)
 *
 * Returns:
 *     BCM_E_XXX
 */

int
bcm_esw_field_action_add(int unit,
                         bcm_field_entry_t entry,
                         bcm_field_action_t action,
                         uint32 param0,
                         uint32 param1)
{
    _field_control_t    *fc;           /* Field control structure. */
    _field_action_t     *fa = NULL;    /* Field action descriptor. */
    int                 rv;            /* Operation return status. */

    FP_VVERB(("FP(unit %d) vverb: bcm_field_action_add(entry=%d, action=%s, \
        p0=%d, p1=%d)\n", unit, entry, \
        _field_action_name(action), param0, param1));

    if ((action == bcmFieldActionRedirectPbmp) ||
        (action == bcmFieldActionEgressMask) ||
        (action == bcmFieldActionEgressPortsAdd) ||
        (action == bcmFieldActionRedirectBcastPbmp)) {
        FP_ERR(("FP(unit %d) Error: Use bcm_field_action_ports_add api.\n", unit));
        return (BCM_E_PARAM);
    }

    /* Adapt action parameters */
    rv = _field_params_api_to_hw_adapt(unit, action, &param0, &param1);
    BCM_IF_ERROR_RETURN(rv);

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* 
     * Allocate the action descriptor, param2 and param3 are not valid here.
     */
    rv = _field_action_alloc(unit, action, param0, param1, 0, 0, &fa);
    if (BCM_FAILURE(rv)) {
        FP_ERR(("FP(unit %d) Error: failure in _field_action_alloc()\n", unit));
        FP_UNLOCK(fc);
        return rv;
    }

    /*
     * Add action to entry actions list.
     */
    rv = _field_action_add(unit, fc, entry, fa);
    FP_UNLOCK(fc);
    if (BCM_FAILURE(rv)) {
        sal_free(fa);
        return rv;
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_action_mac_add
 * Purpose:
 *      Add an action to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry Id.
 *      action - (IN) Field action id.
 *      mac - (IN) Field action parameter.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_action_mac_add(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_action_t action, 
    bcm_mac_t mac)
{
    uint32  param[_FP_ACTION_PARAM_SZ];     

    if ((action != bcmFieldActionSrcMacNew) && 
        (action != bcmFieldActionDstMacNew)) {
        return (BCM_E_PARAM);
    }

    SAL_MAC_ADDR_TO_UINT32(mac, param);

    return bcm_esw_field_action_add(unit, entry, action,
                                    param[0],param[1]);
}


/*
 * Function: bcm_esw_field_action_ports_add
 *
 * Purpose:
 *     Add PBMP related actions, when entry rule is matched for a packet
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - entry ID
 *     action - bcmFieldActionRedirectPbmp or
 *              bcmFieldActionEgressMask or
 *              bcmFieldActionEgressPortsAdd or
 *              bcmFieldActionRedirectBcastPbmp
 *     pbmp - Port Bitmap for the action
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found
 *     BCM_E_MEMORY    - Allocation failure
 *     BCM_E_PARAM     - Incorrect action parameter
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_action_ports_add(int unit,
                               bcm_field_entry_t entry,
                               bcm_field_action_t action,
                               bcm_pbmp_t pbmp)
{
    uint32  param[_FP_ACTION_PARAM_SZ];     

    if ((action != bcmFieldActionRedirectPbmp) && 
        (action != bcmFieldActionEgressMask) &&
        (action != bcmFieldActionEgressPortsAdd) &&
        (action != bcmFieldActionRedirectBcastPbmp)) {
        FP_ERR(("FP(unit %d) Error: Incorrect action parameter\n", unit));
        return (BCM_E_PARAM);
    }

    sal_memset(&param, 0, sizeof(param));

    param[0] = SOC_PBMP_WORD_GET(pbmp, 0);
#if defined(BCM_RAPTOR_SUPPORT) || defined (BCM_TRIUMPH_SUPPORT)
    if (soc_feature(unit, soc_feature_table_hi)) {
        param[1] = SOC_PBMP_WORD_GET(pbmp, 1);
        /* Trident device can support more than 64-ports */
        if (SOC_IS_TD_TT(unit)) {
            param[2] = SOC_PBMP_WORD_GET(pbmp, 2);
        }
    }
#endif /* BCM_RAPTOR_SUPPORT || BCM_TRIUMPH_SUPPORT */
    
    return _bcm_field_action_ports_add(unit, entry, action, 
                param[0], param[1], param[2], 0);
}

/*
 * Function: bcm_esw_field_action_get
 *
 * Purpose:
 *     Get parameters associated with an entry action
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Entry ID
 *     action - Action to perform (bcmFieldActionXXX)
 *     param0 - (OUT) Action parameter
 *     param1 - (OUT) Action parameter
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found
 *     BCM_E_NOT_FOUND - No matching Action for entry
 *     BCM_E_PARAM     - paramX is NULL
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_action_get(int unit,
                         bcm_field_entry_t entry,
                         bcm_field_action_t action,
                         uint32 *param0,
                         uint32 *param1)
{
    _field_entry_t      *f_ent;
    _field_action_t     *fa;
    _field_control_t    *fc;
    int                 rv;

    /* Input parameters check. */
    if ((NULL == param0) || (NULL == param1)) {
            return (BCM_E_PARAM);
        }

    /* Lock the module. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Find matching action in the entry */
    for (fa = f_ent->actions; fa != NULL; fa = fa->next) {
        if (fa->action == action) {
            break;
        }
    }

    if (fa == NULL) {
        FP_UNLOCK(fc);
        FP_ERR(("FP(unit %d) Error: action not in entry=%d\n", unit, entry));
        return (BCM_E_NOT_FOUND);
    }

    *param0 = fa->param[0];
    *param1 = fa->param[1];

    /* Unlock the module. */
    FP_UNLOCK(fc);

    /* Adapt action parameters */
    rv = _field_params_hw_to_api_adapt(unit, action, param0, param1);
    return (rv);
}

/*
 * Function: bcm_esw_field_action_ports_get
 *
 * Purpose:
 *     Get parameters associated with port related entry actions
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Entry ID
 *     action - Action
 *     pbmp - (OUT) Action parameter
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found
 *     BCM_E_NOT_FOUND - No matching Action for entry
 *     BCM_E_PARAM     - incorrect action OR pbmp is NULL
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_action_ports_get(int unit,
                               bcm_field_entry_t entry,
                               bcm_field_action_t action,
                               bcm_pbmp_t *pbmp)
{

    uint32 param[_FP_ACTION_PARAM_SZ];     
    int               rv;

    /* Input parameter check. */
    if (NULL == pbmp) {
        return (BCM_E_PARAM);
    }

    if ((action != bcmFieldActionRedirectPbmp) && 
        (action != bcmFieldActionEgressMask) &&
        (action != bcmFieldActionRedirectBcastPbmp) &&
        (action != bcmFieldActionEgressPortsAdd)) {
        return (BCM_E_PARAM);
    }

    /* Extract action information from field entry. */
    rv = _bcm_field_action_ports_get(unit, entry,
            action, param, param + 1, param + 2, param + 3);
    BCM_IF_ERROR_RETURN(rv);

    BCM_PBMP_CLEAR(*pbmp);
    SOC_PBMP_WORD_SET(*pbmp, 0, param[0]);

#if defined(BCM_RAPTOR_SUPPORT) || defined (BCM_TRIUMPH_SUPPORT)
    if (soc_feature(unit, soc_feature_table_hi)) {
        SOC_PBMP_WORD_SET(*pbmp, 1, param[1]);
        if (SOC_IS_TD_TT(unit)) {
            SOC_PBMP_WORD_SET(*pbmp, 2, param[2]);
        }
    }
#endif /* BCM_RAPTOR_SUPPORT || BCM_TRIUMPH_SUPPORT */
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_action_mac_get
 * Purpose:
 *      Retrieve the parameters for an action previously added to a
 *      field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry Id.
 *      action - (IN) Field action id.
 *      mac - (IN) Field action argument.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_action_mac_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_action_t action, 
    bcm_mac_t *mac)
{
    uint32 param[_FP_ACTION_PARAM_SZ];     
    int    rv;

    /* Input parameter check. */
    if (NULL == mac) {
        return (BCM_E_PARAM);
    }

    if ((action != bcmFieldActionSrcMacNew) && 
        (action != bcmFieldActionDstMacNew)) {
        return (BCM_E_PARAM);
    }
    
    /* Extract action information from field entry. */
    rv = bcm_esw_field_action_get(unit, entry, action, 
                                  param, param + 1);
    BCM_IF_ERROR_RETURN(rv);

    SAL_MAC_ADDR_FROM_UINT32((*mac), param);
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_field_action_delete
 * Purpose:
 *      Delete an action from a field entry.
 * Parameters:
 *      unit   - (IN) BCM device number
 *      entry  - (IN) Entry ID
 *      action - (IN) Action to remove (bcmFieldActionXXX)
 *      param0 - (IN) Action parameter (use 0 if not required)
 *      param1 - (IN) Action parameter (use 0 if not required)
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_action_delete(int unit, bcm_field_entry_t entry, 
                        bcm_field_action_t action, 
                        uint32 param0, uint32 param1)
{
    _field_control_t *fc;  /* Field control structure. */
    int rv;                /* Operation return status. */

    if (action < 0 || bcmFieldActionCount <= action) {
        FP_ERR(("FP(unit %d) Error: unknown action=%d\n", unit, action));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    /* Adapt action parameters */
    rv = _field_params_api_to_hw_adapt(unit, action, &param0, &param1);
    BCM_IF_ERROR_RETURN(rv);

    FP_LOCK(fc);

    rv = _field_action_delete(unit, entry, action, param0, param1);

    FP_UNLOCK(fc);
    return rv;
}




/*
 * Function: bcm_esw_field_action_remove
 *
 * Purpose:
 *     Remove an action performed when entry rule is matched for a packet.
 *
 * Parameters:
 *     unit   - BCM device number
 *     entry  - Entry ID
 *     action - Action to remove (bcmFieldActionXXX)
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found
 *     BCM_E_NOT_FOUND - No matching Action for entry
 *     BCM_E_PARAM     - Action out of valid range.
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_action_remove(int unit,
                            bcm_field_entry_t entry,
                            bcm_field_action_t action)
{
    _field_control_t *fc;  /* Field control structure. */
    int rv;                /* Operation return status. */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = bcm_esw_field_action_delete(unit, entry, action, 
                                     (uint32)_FP_INVALID_INDEX, 
                                     (uint32)_FP_INVALID_INDEX);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_action_remove_all
 *
 * Purpose:
 *     Remove all actions from an entry rule.
 *
 * Parameters:
 *     unit - BCM device number
 *     entry - Entry ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM Unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_action_remove_all(int unit,
                                bcm_field_entry_t entry)
{
    _field_entry_t      *f_ent;
    _field_action_t     *fa;
    _field_control_t    *fc;      /* Field control structure.  */
    int                  rv;      /* Operation return status.  */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }


    /* start at the head of the actions list and burn them up */
    fa = f_ent->actions;

    while (fa != NULL) {
        rv = _field_action_delete(unit, entry, fa->action, 
                                  fa->param[0], fa->param[1]);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* 
         * Action might be removed from the entry actions
         * list only if entry was not installed.
         * Otherwise clean up will happen during reinstall.
         */
        fa = (f_ent->flags & _FP_ENTRY_INSTALLED) ? \
            fa->next : f_ent->actions;
    }

    f_ent->flags |= _FP_ENTRY_DIRTY;

    FP_UNLOCK(fc);
    return (rv);
}

/* Section: Field Statistics */

/*
 * Function: 
 *    bcm_esw_field_stat_create
 *
 * Description:
 *       Create statistics collection entity.
 * Parameters:
 *      unit     - (IN) BCM device number.
 *      group    - (IN) Field group id. 
 *      nstat    - (IN) Number of elements in stat array.
 *      stat_arr - (IN) Collected statistics descriptors array.
 *      stat_id  - (OUT) Statistics entity id.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_create(int unit, bcm_field_group_t group, int nstat, 
                          bcm_field_stat_t *stat_arr, int *stat_id) 
{
    _field_control_t    *fc;      /* Field control structure.  */
    int                  rv;      /* Operation return status.  */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_stat_create(unit, group, nstat, stat_arr, 0, stat_id);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *    bcm_esw_field_stat_create_id
 *
 * Description:
 *       Create statistics collection entity with specified ID.
 * Parameters:
 *      unit     - (IN) BCM device number.
 *      group    - (IN) Field group id. 
 *      nstat    - (IN) Number of elements in stat array.
 *      stat_arr - (IN) Collected statistics descriptors array.
 *      stat_id  - (IN) Statistics entity id.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_create_id(int unit, bcm_field_group_t group, int nstat, 
                          bcm_field_stat_t *stat_arr, int stat_id) 
{
    _field_control_t    *fc;      /* Field control structure.  */
    int                  rv;      /* Operation return status.  */
    int                  stat_id_local = stat_id; /* Stats ID value */

    /* Check if Stat ID is in software supported range */
    if ((stat_id < _FP_ID_BASE) || (stat_id > _FP_ID_MAX)) {
        return (BCM_E_PARAM);
    }
    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_stat_create(unit, group, nstat, stat_arr,
            _FP_STAT_CREATE_ID, &stat_id_local);

    FP_UNLOCK(fc);
    return (rv);
}

#if defined(BCM_KATANA_SUPPORT)
/*
 * Function:
 *      _bcm_esw_field_stat_get_table_info
 * Description:
 *      Provides relevant flex table information(table-name,index with
 *      direction)  for given stat_id
 *
 * Parameters:
 *      unit             - (IN) unit number
 *      Stat_id          - (IN) Statistics entity ID.
 *      num_of_tables    - (OUT) Number of flex counter tables
 *      table_info       - (OUT) Flex counter tables information
 *
 * Return Value:
 *      BCM_E_XXX
 * Notes:
 *     
 */

STATIC int
_bcm_esw_field_stat_get_table_info(int unit, uint32 stat_id,
                                   uint32 *num_of_tables,
                                   bcm_stat_flex_table_info_t *table_info)
{
    _field_stat_t    *f_st=NULL;    /* Field statistics entity.  */
    _field_control_t *fc=NULL;      /* Field control structure.  */

     (*num_of_tables)=0;

     if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
          return BCM_E_UNAVAIL;
     }
     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
     BCM_IF_ERROR_RETURN(_bcm_field_stat_get(unit, stat_id, &f_st));
     table_info[*num_of_tables].table= VFP_POLICY_TABLEm;
     table_info[*num_of_tables].index=f_st->tcam_index;
     table_info[*num_of_tables].direction=bcmStatFlexDirectionIngress;
     (*num_of_tables)++;
     return BCM_E_NONE;
}
#endif

/*
 * Function:
 *      bcm_esw_field_stat_attach
 * Description:
 *      Attach counters entries to a field group 
 *
 * Parameters:
 *      unit             - (IN) unit number
 *      group            - (IN) Field group statistics entity will be
 *                              Associated with in the future 
 *      Stat_counter_id  - (IN) Stat Counter ID.
 *      Stat_id          - (OUT) Statistics entity ID.
 *
 * Return Value:
 *      BCM_E_XXX
 * Notes:
 *
 */

int
bcm_esw_field_stat_attach(int unit, bcm_field_group_t field_group, 
                          uint32 stat_counter_id, uint32 *stat_id)
{
#if defined(BCM_KATANA_SUPPORT)
    soc_mem_t                    table=0;
    bcm_stat_flex_direction_t    direction=bcmStatFlexDirectionIngress;
    uint32                       pool_number=0;
    uint32                       base_index=0;
    bcm_stat_flex_mode_t         offset_mode=0;
    bcm_stat_object_t            object=bcmStatObjectIngPort;
    bcm_stat_group_mode_t        group_mode= bcmStatGroupModeSingle;
    bcm_field_stat_t             field_stat[2]={bcmFieldStatBytes,
                                             bcmFieldStatPackets};
    bcm_stat_flex_ingress_mode_t flex_ingress_mode={0};
    _field_stat_t                *f_st=NULL;    /* Field statistics entity.  */
    _field_control_t             *fc=NULL;      /* Field control structure.  */
    int                          rv=0;          /* Operation return status.  */

    if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
         return BCM_E_UNAVAIL;
    }

    _bcm_esw_stat_get_counter_id_info(
                  stat_counter_id,
                  &group_mode,&object,&offset_mode,&pool_number,&base_index);
        /* Validate object id first */
    if (!((object >= bcmStatObjectIngPort) &&
          (object <= bcmStatObjectEgrL3Intf))) {
           soc_cm_print("Invalid bcm_stat_object_t passed %d \n",object);
           return BCM_E_PARAM;
    }
    /* Validate group_mode */
    if(!((group_mode >= bcmStatGroupModeSingle) &&
         (group_mode <= bcmStatGroupModeDvpType))) {
          soc_cm_print("Invalid bcm_stat_group_mode_t passed %d \n",group_mode);
          return BCM_E_PARAM;
    }
    BCM_IF_ERROR_RETURN(bcm_esw_stat_flex_get_table_info(
                        object,&table,&direction));
    if (!((direction == bcmStatFlexDirectionIngress) &&
          (table == VFP_POLICY_TABLEm))) {
           return BCM_E_PARAM;
    }
    BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_ingress_mode_info(
                        unit,offset_mode,&flex_ingress_mode));
    BCM_IF_ERROR_RETURN(bcm_esw_field_stat_create(
                        unit, field_group, 2, field_stat, (int *)stat_id));
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);
    rv = _bcm_field_stat_get(unit, *stat_id, &f_st);
    if(BCM_FAILURE(rv)) {
       FP_UNLOCK(fc);
       bcm_esw_field_stat_destroy(unit,*stat_id);
       return rv;
    }
    FP_UNLOCK(fc);
    f_st->flex_mode = stat_counter_id;
    return BCM_E_NONE;
#else
    return BCM_E_UNAVAIL;
#endif
}

/*
 * Function:
 *      bcm_esw_field_stat_detach
 * Description:
 *      Detach counters entries to a field group. 
 *
 * Parameters:
 *      unit             - (IN) unit number
 *      Stat_id          - (IN) Statistics entity ID.
 *
 * Return Value:
 *      BCM_E_XXX
 * Notes:
 *
 */

int
bcm_esw_field_stat_detach(int unit, uint32 stat_id)
{
#if defined(BCM_KATANA_SUPPORT)
    uint32                     count=0;
    uint32                     num_of_tables=0;
    bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
    _field_stat_t              *f_st=NULL;    /* Field statistics entity.  */
    _field_control_t           *fc=NULL;      /* Field control structure.  */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    BCM_IF_ERROR_RETURN(_bcm_field_stat_get(unit, stat_id, &f_st));
    BCM_IF_ERROR_RETURN(_bcm_esw_field_stat_get_table_info(
                        unit, stat_id,&num_of_tables,&table_info[0]));

    for (count=0; count < num_of_tables ; count++) {
      if (table_info[count].direction == bcmStatFlexDirectionIngress) {
           BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_detach_ingress_table_counters(
                               unit,
                               table_info[count].table,
                               table_info[count].index));
           f_st->flex_mode = 0;
           return BCM_E_NONE;
      }
    }
    return BCM_E_NOT_FOUND;
#else
    return BCM_E_UNAVAIL;
#endif
}

/*
 * Function:
 *      bcm_esw_field_stat_counter_get
 * Description:
 *      Get counter statistic values for a field entity
 *
 * Parameters:
 *      unit             - (IN) unit number
 *      Stat_id          - (IN) Statistics entity ID.
 *      stat             - (IN) Type of the counter to retrieve
 *                              I.e. ingress/egress byte/packet)
 *      num_entries      - (IN) Number of counter Entries
 *      counter_indexes  - (IN) Pointer to Counter indexes entries
 *      counter_values   - (OUT) Pointer to counter values
 *
 * Return Value:
 *      BCM_E_XXX
 * Notes:
 *
 */

int
bcm_esw_field_stat_counter_get(int unit, uint32 stat_id, bcm_field_stat_t stat, 
                               uint32 num_entries, uint32 *counter_indexes, 
                               bcm_stat_value_t *counter_values)
{
#if defined(BCM_KATANA_SUPPORT)
    uint32                          table_count=0;
    uint32                          index_count=0;
    uint32                          num_of_tables=0;
    bcm_stat_flex_direction_t       direction=bcmStatFlexDirectionIngress;
    uint32                          byte_flag=0;
    bcm_stat_flex_table_info_t      table_info[
                                    BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];

    if (stat == bcmFieldStatPackets) {
        byte_flag=0;
    } else {
        byte_flag=1;
    }
    BCM_IF_ERROR_RETURN(_bcm_esw_field_stat_get_table_info(
                        unit, stat_id,&num_of_tables,&table_info[0]));

    for (table_count=0; table_count < num_of_tables ; table_count++) {
         if (table_info[table_count].direction == direction) {
             for (index_count=0; index_count < num_entries ; index_count++) {
                  BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get(
                                      unit,
                                      table_info[table_count].index,
                                      table_info[table_count].table,
                                      byte_flag,
                                      counter_indexes[index_count],
                                      &counter_values[index_count]));
             }
         }
    }
    return BCM_E_NONE;
#else
    return BCM_E_UNAVAIL;
#endif
}

/*
 * Function:
 *      bcm_esw_field_stat_counter_set
 * Description:
 *      Set counter statistic values for a field entity 
 *
 * Parameters:
 *      unit             - (IN) unit number
 *      Stat_id          - (IN) Statistics entity ID.
 *      stat             - (IN) Type of the counter to retrieve
 *                              I.e. ingress/egress byte/packet)
 *      num_entries      - (IN) Number of counter Entries
 *      counter_indexes  - (IN) Pointer to Counter indexes entries
 *      counter_values   - (IN) Pointer to counter values
 *
 * Return Value:
 *      BCM_E_XXX
 * Notes:
 *
 */
int
bcm_esw_field_stat_counter_set(int unit, uint32 stat_id, bcm_field_stat_t stat, 
                               uint32 num_entries, uint32 *counter_indexes, 
                               bcm_stat_value_t *counter_values)
{
#if defined(BCM_KATANA_SUPPORT)
    uint32                          table_count=0;
    uint32                          index_count=0;
    uint32                          num_of_tables=0;
    bcm_stat_flex_direction_t       direction=bcmStatFlexDirectionIngress;
    uint32                          byte_flag=0;
    bcm_stat_flex_table_info_t      table_info[
                                    BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];

    if (stat == bcmFieldStatPackets) {
        byte_flag=0;
    } else {
        byte_flag=1;
    }
    BCM_IF_ERROR_RETURN(_bcm_esw_field_stat_get_table_info(
                        unit, stat_id,&num_of_tables,&table_info[0]));

    for (table_count=0; table_count < num_of_tables ; table_count++) {
         if (table_info[table_count].direction == direction) {
             for (index_count=0; index_count < num_entries ; index_count++) {
                  BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set(
                                      unit,
                                      table_info[table_count].index,
                                      table_info[table_count].table,
                                      byte_flag,
                                      counter_indexes[index_count],
                                      &counter_values[index_count]));
             }
         }
    }
    return BCM_E_NONE;
#else
    return BCM_E_UNAVAIL;
#endif
}
/*
 * Function:
 *      bcm_esw_field_stat_id_get
 * Description:
 *      Get stat counter id associated with given gpo
 *
 * Parameters:
 *      unit             - (IN) unit number
 *      Stat_id          - (IN) Statistics entity ID.
 *      stat             - (IN) Type of the counter to retrieve
 *                              I.e. ingress/egress byte/packet)
 *      Stat_counter_id  - (OUT) Stat Counter ID
 * Return Value:
 *      BCM_E_XXX
 * Notes:
 *
 */
int bcm_esw_field_stat_id_get(int               unit,
                              bcm_field_group_t group,
                              bcm_field_stat_t  stat, 
                              uint32            *stat_counter_id)
{
   /* Not Required */
   return BCM_E_UNAVAIL;
}



/*
 * Function: 
 *    bcm_esw_field_stat_destroy
 *
 * Description:
 *       Destroy statistics collection entity.
 * Parameters:
 *      unit     - (IN) BCM device number.
 *      stat_id  - (IN) Statistics entity id.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_destroy(int unit, int stat_id)
{
    _field_control_t    *fc;      /* Field control structure.  */
    int                  rv;      /* Operation return status.  */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_stat_destroy(unit, stat_id);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *     bcm_esw_field_stat_size
 *
 * Description:
 *      Get number of different statistics associated with statistics
 *      collection entity.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      stat_id   - (IN) Statistics entity id.
 *      stat_size - (OUT) Number of collercted statistics
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_size(int unit, int stat_id, int *stat_size)
{
    _field_stat_t       *f_st;    /* Field statistics entity.  */
    _field_control_t    *fc;      /* Field control structure.  */
    int                  rv;      /* Operation return status.  */

    /* Input parameters check */
    if (NULL == stat_size) {
        return (BCM_E_PARAM);
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_stat_get(unit, stat_id, &f_st);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    *stat_size = f_st->nstat; 

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *     bcm_esw_field_stat_config_get
 *
 * Description:
 *      Get enabled statistics for specific collection entity.
 * Parameters:
 *      unit     - (IN) BCM device number.
 *      stat_id  - (IN) Statistics entity id.
 *      nstat    - (IN) Number of elements in stat array.
 *      stat_arr - (OUT) Collected statistics descriptors array.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_config_get(int unit, int stat_id, int nstat, 
                              bcm_field_stat_t *stat_arr)
{
    _field_stat_t       *f_st;     /* Field statistics entity.   */
    _field_control_t    *fc;       /* Field control structure.   */
    int                 stat_count;/* Number of elements to fill.*/
    int                 rv;        /* Operation return status.   */

    /* Input parameters check. */
    if ((NULL == stat_arr) || (nstat <= 0) || (nstat > _bcmFieldStatCount)) {
        return (BCM_E_PARAM);
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_stat_get(unit, stat_id, &f_st);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }


    /* Initialize application provided array. */
    sal_memset(stat_arr, 0, (nstat * sizeof(bcm_field_stat_t)));

    /* Number of items to copy. */
    stat_count = (nstat > f_st->nstat) ? f_st->nstat : nstat;

    sal_memcpy(stat_arr, f_st->stat_arr, 
               (stat_count * sizeof(bcm_field_stat_t)));

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *      bcm_esw_field_stat_set
 *
 * Description:
 *      Set 64 bit counter value for specific statistic type.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      stat_id   - (IN) Statistics entity id.
 *      stat      - (IN) Collected statistics descriptor.
 *      value     - (OUT) Collected counters value.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_set(int unit, int stat_id, bcm_field_stat_t stat, 
                       uint64 value)
{
    _field_stat_t       *f_st;     /* Field statistics entity.   */
    _field_control_t    *fc;       /* Field control structure.   */
    int                 rv;        /* Operation return status.   */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get statistics entity descriptor. */
    rv = _bcm_field_stat_get(unit, stat_id, &f_st);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Write specific counter only if statistics entity was installed. */
    if (_FP_INVALID_INDEX == f_st->hw_index)  {
        if (COMPILER_64_IS_ZERO(value)) {
            rv = BCM_E_NONE;
        } else {
            rv = BCM_E_UNAVAIL;
        }
    } else {
        rv = _field_stat_value_set(unit, f_st, stat, value);
    }

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *      bcm_esw_field_stat_set32
 *
 * Description:
 *      Set lower 32 bit counter value for specific statistic type.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      stat_id   - (IN) Statistics entity id.
 *      stat      - (IN) Collected statistics descriptor.
 *      value     - (OUT) Collected counters value.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_set32(int unit, int stat_id, 
                         bcm_field_stat_t stat, uint32 value)
{
    uint64 val64;

    COMPILER_64_SET(val64, 0, value);
    return bcm_esw_field_stat_set (unit, stat_id, stat, val64);
}

/*
 * Function: 
 *      bcm_esw_field_stat_all_set
 *
 * Description:
 *      Set 64 bit counter values for all statistic types.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      stat_id   - (IN) Statistics entity id.
 *      nstat     - (IN) Number of elements in stat array.
 *      stat_arr  - (IN) Collected statistics descriptors array.
 *      value_arr - (OUT) Collected counters values.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_all_set(int unit, int stat_id, uint64 value)
{
    _field_control_t    *fc;       /* Field control structure.    */
    _field_stat_t       *f_st;     /* Field statistics entity.    */
    int                 idx;       /* Statistics iteration index. */
    int                 rv;        /* Operation return status.    */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_stat_get(unit, stat_id, &f_st);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Read individual statistics. */
    for (idx = 0; idx < f_st->nstat; idx++) {
        rv = bcm_esw_field_stat_set(unit, stat_id, f_st->stat_arr[idx], value);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
    }

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *      bcm_esw_field_stat_all_set32
 *
 * Description:
 *      Set 64 bit counter values for all statistic types.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      stat_id   - (IN) Statistics entity id.
 *      nstat     - (IN) Number of elements in stat array.
 *      stat_arr  - (IN) Collected statistics descriptors array.
 *      value_arr - (OUT) Collected counters values.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_all_set32(int unit, int stat_id, uint32 value)
{
    uint64              val64;     /* 64 bit value. */

    COMPILER_64_SET(val64, 0, value);
    return bcm_esw_field_stat_all_set(unit, stat_id, val64);
}

/*
 * Function: 
 *      bcm_esw_field_stat_get
 *
 * Description:
 *      Get 64 bit counter value for specific statistic type.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      stat_id   - (IN) Statistics entity id.
 *      stat      - (IN) Collected statistics descriptor.
 *      value     - (OUT) Collected counters value.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_get(int unit, int stat_id, bcm_field_stat_t stat, 
                       uint64 *value)
{
    _field_stat_t       *f_st;     /* Field statistics entity.   */
    _field_control_t    *fc;       /* Field control structure.   */
    int                 rv;        /* Operation return status.   */

    /* Input parameters check. */
    if (NULL == value) {
        return (BCM_E_PARAM);
    }

    COMPILER_64_ZERO(*value);

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get statistics entity descriptor. */
    rv = _bcm_field_stat_get(unit, stat_id, &f_st);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Read specific counter only if statistics entity was installed. */
    if (_FP_INVALID_INDEX != f_st->hw_index) {
        rv = _field_stat_value_get(unit, f_st, stat, value);
    }

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *      bcm_esw_field_stat_get32
 *
 * Description:
 *      Get lower 32 bit counter value for specific statistic type.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      stat_id   - (IN) Statistics entity id.
 *      stat      - (IN) Collected statistics descriptor.
 *      value     - (OUT) Collected counters value.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_get32(int unit, int stat_id, 
                         bcm_field_stat_t stat, uint32 *value)
{
    uint64 val64;            /* 64 bit counter value.    */
    int rv;                  /* Operation return status. */

    /* Input parameters check. */
    if (NULL == value) {
        return (BCM_E_PARAM);
    }

    /* Read 64 bit counter value. */
    rv = bcm_esw_field_stat_get (unit, stat_id, stat, &val64);
    if (BCM_SUCCESS(rv)) {
        *value = COMPILER_64_LO(val64);
    } 
    return rv;
}

/*
 * Function: 
 *      bcm_esw_field_stat_multi_get
 *
 * Description:
 *      Get 64 bit counter values for multiple statistic types.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      stat_id   - (IN) Statistics entity id.
 *      nstat     - (IN) Number of elements in stat array.
 *      stat_arr  - (IN) Collected statistics descriptors array.
 *      value_arr - (OUT) Collected counters values.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_multi_get(int unit, int stat_id, int nstat, 
                             bcm_field_stat_t *stat_arr, uint64 *value_arr)
{
    _field_control_t    *fc;       /* Field control structure.    */
    int                 rv;        /* Operation return status.    */
    int                 idx;       /* Statistics iteration index. */

    /* Input parameters check. */
    for (idx = 0; idx < nstat; idx++) {
        if ((NULL == stat_arr + idx) ||
            (NULL == value_arr + idx)) {
            return (BCM_E_PARAM);
        }
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Read individual statistics. */
    for (idx = 0; idx < nstat; idx++) {
        rv = bcm_esw_field_stat_get(unit, stat_id, stat_arr[idx], 
                                    value_arr + idx);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
    }

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: 
 *      bcm_esw_field_stat_multi_get32
 *
 * Description:
 *      Get lower 32 bit counter values for multiple statistic types.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      stat_id   - (IN) Statistics entity id.
 *      nstat     - (IN) Number of elements in stat array.
 *      stat_arr  - (IN) Collected statistics descriptors array.
 *      value_arr - (OUT) Collected counters values.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_stat_multi_get32(int unit, int stat_id, int nstat, 
                               bcm_field_stat_t *stat_arr, 
                               uint32 *value_arr)
{
    _field_control_t    *fc;       /* Field control structure.    */
    uint64              value;     /* 64 bit counter value.       */
    int                 rv;        /* Operation return status.    */
    int                 idx;       /* Statistics iteration index. */

    /* Input parameters check. */
    for (idx = 0; idx < nstat; idx++) {
        if ((NULL == stat_arr + idx) ||
            (NULL == value_arr + idx)) {
            return (BCM_E_PARAM);
        }
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Read individual statistics. */
    for (idx = 0; idx < nstat; idx++) {
        rv = bcm_esw_field_stat_get(unit, stat_id, stat_arr[idx], &value);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
        value_arr[idx] = COMPILER_64_LO(value);
    }

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: 
 *      bcm_esw_field_entry_stat_attach
 *
 * Description:
 *       Attach statistics entity to Field Processor entry.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      entry     - (IN) Field entry id. 
 *      stat_id   - (IN) Statistics entity id.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_entry_stat_attach(int unit, bcm_field_entry_t entry, 
                                int stat_id)
{
    _field_entry_t      *f_ent;   /* Internal entry descriptor.       */
    _field_control_t    *fc;      /* Field control structure.  */
    int                  rv;      /* Operation return status.  */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get entry description structure. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Attach statistics entity to the entry. */
    rv = _field_entry_stat_attach(unit, f_ent, stat_id);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *      bcm_esw_field_entry_stat_detach
 *
 * Description:
 *       Detach statistics entity to Field Processor entry.
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      entry     - (IN) Field entry id. 
 *      stat_id   - (IN) Statistics entity id.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_entry_stat_detach(int unit, bcm_field_entry_t entry,
                                int stat_id)
{
        _field_entry_t      *f_ent;   /* Field entry structure.    */
    _field_control_t    *fc;      /* Field control structure.  */
    int                  rv;      /* Operation return status.  */

    /* Get field control structure. */
        BCM_IF_ERROR_RETURN (_field_control_get(unit, &fc));
        FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
        if (BCM_FAILURE(rv)) {
           FP_UNLOCK(fc);
           return (rv);
        }

    rv = _field_entry_stat_detach(unit, f_ent, stat_id);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: 
 *      bcm_esw_field_entry_stat_get
 *
 * Description:
 *      Get statistics entity attached to Field Processor entry.  
 * Parameters:
 *      unit      - (IN) BCM device number.
 *      entry     - (IN) Field entry id. 
 *      stat_id   - (IN) Statistics entity id.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_entry_stat_get(int unit, bcm_field_entry_t entry, int *stat_id)
{
    _field_control_t    *fc;       /* Field control structure.   */
    _field_entry_t      *f_ent;    /* Field entry structure.     */
    int                 rv;        /* Operation return status.   */

    /* Input parameters check. */
    if (NULL == stat_id) {
        return (BCM_E_PARAM);
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get field processor entry structure. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    if (f_ent->statistic.flags & _FP_ENTRY_STAT_VALID) {
        *stat_id = f_ent->statistic.sid; 
    } else {
        rv = BCM_E_NOT_FOUND;
    }

    FP_UNLOCK(fc);
    return (rv);
}
/* Section: Field Counters */

/*
 * Function: bcm_esw_field_counter_create
 *
 * Description:
 *      Create a field counter pair within an entry.
 *
 * Parameters:
 *      unit  - (IN) BCM device number.
 *      entry - (IN) Entry ID.
 *
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_counter_create(int unit, bcm_field_entry_t entry)
{
    int                  rv;           /* Operation return value.    */
    int                  stat_id;      /* Statistics entity.         */
    _field_entry_t       *f_ent;       /* Field entry structure.     */
    _field_control_t     *fc;          /* Field control structure.   */


    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc); 

    /* Get field entry control structure. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Create statistics collection entity. */
    rv = _field_stat_create(unit, f_ent->group->gid, 0, NULL, 
                            _FP_STAT_INTERNAL, &stat_id);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Attach statistics collection entity to an entry. */
    rv = _field_entry_stat_attach(unit, f_ent, stat_id);
    if (BCM_FAILURE(rv)) {
        (void)_field_stat_destroy(unit, stat_id);
    }

    /*  Stat should not be installed until 
     *  "bcmFieldActionUpdateCounter" added to the enry. 
     */
    f_ent->statistic.flags |= _FP_ENTRY_STAT_EMPTY;

        FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_counter_share
 *
 * Description:
 *      Share the counter pair from one entry with another entry.
 *
 * Parameters:
 *      unit      - (IN) BCM device number
 *      src_entry - (IN) Entry ID that has counter pair
 *      dst_entry - (IN) Entry ID that will get counter pair
 *
 * Returns:
 *      BCM_E_INIT      - BCM unit not initialized
 *      BCM_E_NOT_FOUND - Either source or destination entry not found
 *      BCM_E_PARAM     - Source and destination are not in the same slice.
 *      BCM_E_EXISTS    - Destination entry already has counter.
 *      BCM_E_EMPTY     - No source counter exists.
 *      BCM_E_NONE      - Success
 *
 * Notes:
 *     The src_entry and dst_entry should belong to the same field group
 */

int
bcm_esw_field_counter_share(int unit,
                            bcm_field_entry_t src_entry,
                            bcm_field_entry_t dst_entry)
{
    _field_control_t  *fc;          /* Field control structure. */
    int               stat_id;      /* Statistics entity id.    */
    int               rv;           /* Operation return status. */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Read policer id from source entry. */
    rv = bcm_esw_field_entry_stat_get(unit, src_entry,  &stat_id);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Attach policer to a destination entry. */
    rv = bcm_esw_field_entry_stat_attach(unit, dst_entry, stat_id);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_counter_destroy
 *
 * Description:
 *     Remove a counter pair from an entry. If no other entries reference
 *     the counter, it is deallocated.
 *
 * Parameters:
 *     unit  - (IN) BCM device number.
 *     entry - (IN) Entry ID.
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Entry not found.
 *     BCM_E_EMPTY     - No source counter exists.
 *     BCM_E_NONE      - Success
 *
 * Notes:
 *     Counter pair becomes available for reallocation if it
 *     is not associated with any other entry rule.
 */

int
bcm_esw_field_counter_destroy(int unit, bcm_field_entry_t entry)
{
    _field_control_t    *fc;       /* Field control structure.   */
    _field_entry_t      *f_ent;    /* Field entry structure.     */
    int                 rv;        /* Operation return status.   */


    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get field entry structure. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Detach statistic entity from the entry. */
    rv = _field_entry_stat_detach(unit, f_ent, f_ent->statistic.sid);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_counter_set
 *
 * Description:
 *      Set a counter value.
 *
 * Parameters:
 *      unit        - (IN) BCM device number.
 *      entry       - (IN) Entry ID.
 *      counter_num - (IN) Choice of upper (counter_num=1) or lower
 *                         (counter_num=0) of the counter pair.
 *      val         - (IN) Packet/byte counter value
 *
 * Returns:
 *      BCM_E_INIT      - BCM unit not initialized.
 *      BCM_E_NOT_FOUND - Entry ID not found in unit.
 *      BCM_E_EMPTY     - No counter created for entry.
 *      BCM_E_PARAM     - counter_num does not match counter index.
 *      BCM_E_XXX       - From memory write operations.
 *      BCM_E_UNAVAIL   - Feature unavailable on unit.
 *      BCM_E_NONE      - Success
 */

int
bcm_esw_field_counter_set(int unit, bcm_field_entry_t entry,
                          int counter_num, uint64 val)
{
    _field_entry_stat_t   *f_ent_st;  /* Field entry statistics entity. */
    _field_entry_t        *f_ent;     /* Field entry structure.         */
    _field_stat_t         *f_st;      /* Field entry structure.         */
    _field_control_t      *fc;        /* Field control structure.       */
    int                   rv;         /* Operation return status.       */

    if (counter_num < 0) {
        return (BCM_E_PARAM);
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get entry structure. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    f_ent_st = &f_ent->statistic;

    /* Check if counter is attached to an entry. */ 
    if ((0 == (f_ent_st->flags & _FP_ENTRY_STAT_VALID)) ||
        (f_ent_st->flags & _FP_ENTRY_STAT_EMPTY)) {
        FP_UNLOCK(fc);
        return (BCM_E_EMPTY);
    }

    /* Get statistics entity descriptor. */
    rv = _bcm_field_stat_get(unit, f_ent_st->sid, &f_st);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Select counter portion for COUNTER_MODE_YES_NO/NO_YES */
    if (f_ent_st->flags & _FP_ENTRY_STAT_USE_EVEN) {
        counter_num = 0;
    } else if (f_ent_st->flags & _FP_ENTRY_STAT_USE_ODD) {
        counter_num = 1;
    }

    /* Return 0 if statistics is not available. */
    if ((counter_num < 0) || ((counter_num + 1) > f_st->nstat)) {
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }

    /* Read 64 bit counter value. */
    rv = bcm_esw_field_stat_set (unit, f_st->sid, 
                                 f_st->stat_arr[counter_num], val);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_counter_set32
 *
 * Description:
 *      Set a 32-bit counter value.
 *
 * Parameters:
 *      unit        - (IN) BCM device number.
 *      entry       - (IN) Entry ID.
 *      counter_num - (IN) Choice of upper (counter_num=1) or 
 *                                   lower (counter_num=0).
 *                    of the counter pair.
 *      count       - (IN) Packet/byte counter value to set.
 *
 * Returns:
 *      BCM_E_INIT      - BCM unit not initialized.
 *      BCM_E_NOT_FOUND - Entry ID not found in unit.
 *      BCM_E_EMPTY     - No counter created for entry.
 *      BCM_E_PARAM     - counter_num does not match counter index.
 *      BCM_E_XXX       - From memory write operations.
 *      BCM_E_UNAVAIL   - Feature unavailable on unit.
 *      BCM_E_NONE      - Success
 */
int
bcm_esw_field_counter_set32(int unit, bcm_field_entry_t entry, int counter_num,
                            uint32 count)
{
    uint64 count_64;

    COMPILER_64_SET(count_64, 0, count);
 
    return bcm_esw_field_counter_set(unit, entry, counter_num, count_64);
}


/*
 * Function: bcm_esw_field_counter_get
 *
 * Description:
 *      Get a counter value.
 *
 * Parameters:
 *      unit - BCM device number
 *      entry       - (IN) Entry ID
 *      counter_num - (IN) Choice of upper (counter_num=1) or 
 *                                   lower (counter_num=0)
 *                    of the counter pair.
 *      valp        - (OUT) Pointer to counter value
 *
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_counter_get(int unit, bcm_field_entry_t entry,
                          int counter_num, uint64 *valp)
{
    _field_entry_stat_t   *f_ent_st;  /* Field entry statistics entity. */
    _field_entry_t        *f_ent;     /* Field entry structure.         */
    _field_stat_t         *f_st;      /* Field entry structure.         */
    _field_control_t      *fc;        /* Field control structure.       */
    int                   rv;         /* Operation return status.       */

    if (valp == NULL) {
        return (BCM_E_PARAM);
    }

    if (counter_num < 0) {
        return (BCM_E_PARAM);
    }

    COMPILER_64_ZERO(*valp);

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get entry structure. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    f_ent_st = &f_ent->statistic;

    /* Check if counter is attached to an entry. */ 
    if ((0 == (f_ent_st->flags & _FP_ENTRY_STAT_VALID)) ||
        (f_ent_st->flags & _FP_ENTRY_STAT_EMPTY)) {
        FP_UNLOCK(fc);
        return (BCM_E_EMPTY);
    }

    /* Get statistics entity descriptor. */
    rv = _bcm_field_stat_get(unit, f_ent_st->sid, &f_st);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Select counter portion for COUNTER_MODE_YES_NO/NO_YES */
    if (f_ent_st->flags & _FP_ENTRY_STAT_USE_EVEN) {
        counter_num = 0;
    } else if (f_ent_st->flags & _FP_ENTRY_STAT_USE_ODD) {
        counter_num = 1;
    }

    /* Return 0 if statistics is not available. */
    if ((counter_num < 0) || (counter_num > f_st->nstat)) {
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }

    /* Read 64 bit counter value. */
    rv = bcm_esw_field_stat_get (unit, f_st->sid, 
                                 f_st->stat_arr[counter_num], valp);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_counter_get32
 *
 * Description:
 *      Get 32 bits counter value.
 *
 * Parameters:
 *      unit        - (IN) BCM device number.
 *      entry       - (IN) Entry ID.
 *      counter_num - (IN) Choice of upper (counter_num=1) or 
 *                                   lower (counter_num=0)
 *                    of the counter pair.
 *      valp        - (OUT) Pointer to counter value.
 *
 * Returns:
 *      BCM_E_INIT      - BCM unit not initialized.
 *      BCM_E_NOT_FOUND - Entry ID not found in unit.
 *      BCM_E_EMPTY     - No counter created for entry.
 *      BCM_E_PARAM     - counter_num out of range (0 or 1)
 *      BCM_E_PARAM     - valp pointing to NULL.
 *      BCM_E_INTERNAL  - No group for entry??? (should never happen).
 *      BCM_E_XXX       - From memory read operations.
 *      BCM_E_UNAVAIL   - Feature unavailable on unit.
 *      BCM_E_NONE      - Success
 */

int
bcm_esw_field_counter_get32(int unit,
                            bcm_field_entry_t entry,
                            int counter_num,
                            uint32 *valp)
{
    uint64 count_64;
    int rv;

    rv = bcm_esw_field_counter_get(unit, entry, counter_num, &count_64);
    if (BCM_SUCCESS(rv)) {
        *valp = COMPILER_64_LO(count_64);
    } 
    return rv;
}

/* Section Field Policers. */
/*
 * Function:
 *      bcm_esw_policer_init
 * Purpose:
 *      Initialize policer module.
 * Parameters:
 *      unit - (IN) Unit number.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_policer_init(int unit)
{
    return (BCM_E_NONE);
}
/*
 * Function:
 *      bcm_policer_get
 * Purpose:
 *      Get the config settings for a policer entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      policer_id - (IN) Policer ID.
 *      pol_cfg - (OUT) Policer configuration.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_policer_get(int unit, bcm_policer_t policer_id, 
                    bcm_policer_config_t *pol_cfg)
{
    _field_control_t    *fc;     /* Field control structure.     */
    _field_policer_t    *f_pl;   /* Internal policer descriptor. */
    int                 rv;      /* Operation return status.     */

#ifdef BCM_KATANA_SUPPORT
    int offset_mode=0;
#endif
    /* Input parameters check. */
    if (NULL == pol_cfg) {
        return (BCM_E_PARAM);
    }
#ifdef BCM_KATANA_SUPPORT
    if (SOC_IS_KATANA(unit)) {
        offset_mode = ((policer_id & BCM_POLICER_GLOBAL_METER_MODE_MASK) >>
                             BCM_POLICER_GLOBAL_METER_MODE_SHIFT) ;
        if (offset_mode) {   /* Global meter policer */
            rv = _bcm_esw_global_meter_policer_get(unit, policer_id, pol_cfg); 
            return (rv);
        } 
    } 
#endif

    FIELD_IS_INIT(unit);
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    rv = _bcm_field_policer_get(unit, policer_id, &f_pl);
    if (BCM_SUCCESS(rv)) {
        sal_memcpy(pol_cfg, &f_pl->cfg, sizeof(bcm_policer_config_t));
    }

    

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      _bcm_field_meter_pair_mode_get
 * Purpose:
 *      Set the config settings for a policer entry.
 * Parameters:
 *      unit  - (IN) Unit number.
 *      f_pl  - (IN) Policer config.
 *      mode  - (OUT) Meter pair mode.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
_bcm_field_meter_pair_mode_get(int unit, _field_policer_t *f_pl,
                               uint32 *mode)
{
    /* Input parameters check. */
    if ((NULL == f_pl) || (NULL == mode)) {
        return (BCM_E_PARAM);
    }

    switch (f_pl->cfg.mode) {
      case bcmPolicerModeSrTcmModified:
      case bcmPolicerModeSrTcm:
          if (f_pl->cfg.flags & BCM_POLICER_COLOR_BLIND) {
              *mode = BCM_FIELD_METER_MODE_srTCM_COLOR_BLIND;
          } else {
              *mode = BCM_FIELD_METER_MODE_srTCM_COLOR_AWARE;
          }
          break;
      case bcmPolicerModeCommitted:
      case bcmPolicerModePeak:
          *mode = BCM_FIELD_METER_MODE_FLOW;
          break;
      case bcmPolicerModeTrTcm:
          if (f_pl->cfg.flags & BCM_POLICER_COLOR_BLIND) {
              *mode = BCM_FIELD_METER_MODE_trTCM_COLOR_BLIND;
          } else {
              *mode = BCM_FIELD_METER_MODE_trTCM_COLOR_AWARE;
          }
          break;
      case bcmPolicerModeTrTcmDs:
      case bcmPolicerModeCoupledTrTcmDs:
          if (f_pl->cfg.flags & BCM_POLICER_COLOR_BLIND) {
              *mode = 4;
          } else {
              *mode = 5;
          }
          break;
      case bcmPolicerModePassThrough:
          if (SOC_IS_FIREBOLT2(unit)) {
              *mode = 4;
          } else {
              *mode = BCM_FIELD_METER_MODE_DEFAULT;
          }
          break;
      case bcmPolicerModeGreen:
          *mode = BCM_FIELD_METER_MODE_DEFAULT;
          break;
      default:
          break;
    }
    return (BCM_E_NONE);
}


/*
 * Function:
 *      bcm_esw_policer_set
 * Purpose:
 *      Set the config settings for a policer entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      policer_id - (IN) Policer ID.
 *      pol_cfg - (IN) Policer configuration.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_policer_set(int unit, bcm_policer_t policer_id, 
                    bcm_policer_config_t *pol_cfg)
{
    _field_control_t    *fc;     /* Field control structure.     */
    _field_policer_t    *f_pl;   /* Internal policer descriptor. */
    int                 rv;      /* Operation return status.     */
        _field_group_t *fg;                      /* Field group info. */
        _field_stage_t *stage_fc;        /* Stage field control info.*/
        _field_entry_t *f_ent;           /* Internal entry descriptor. */
        _field_entry_policer_t *f_ent_pl; /* Field entry policer structure.*/
        int idx;                                         /* Policers levels iterator. */
        int eid;                                         /*entry ID*/
        int tmp = 0;                             /* Temporary iterator. */

#ifdef BCM_KATANA_SUPPORT
        int offset_mode=0;
#endif
    /* Input parameters check. */
    if (NULL == pol_cfg) {
        return (BCM_E_PARAM);
    }
#ifdef BCM_KATANA_SUPPORT
    if (SOC_IS_KATANA(unit)) {
        offset_mode = ((policer_id & BCM_POLICER_GLOBAL_METER_MODE_MASK) >>
                             BCM_POLICER_GLOBAL_METER_MODE_SHIFT);
        if (offset_mode) {   /* Global meter policer */
            rv = _bcm_esw_global_meter_policer_set(unit, policer_id, pol_cfg); 
            return (rv);
        } 
    } 
#endif
    FIELD_IS_INIT(unit);
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    rv = _bcm_field_policer_get(unit, policer_id, &f_pl);
    if (BCM_SUCCESS(rv)) {
        sal_memcpy(&f_pl->cfg, pol_cfg, sizeof(bcm_policer_config_t));
    }

    /* Set policer "dirty" flags. */
    rv = _field_policer_hw_flags_set(unit, f_pl, 0);

        /*
         * Check if any entries has this policer attached and
         * set the dirty flag for the entry
         */
        fg = fc->groups;
        if (NULL == fg) {
                FP_UNLOCK(fc);
                return (BCM_E_NONE);
        }

        rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
        if (BCM_FAILURE(rv)) {
                FP_UNLOCK(fc);
                return (rv);
        }

        for (fg = fc->groups; fg != NULL; fg = fg->next) {
                tmp = 0;
                /*
                 * Check for all entries where this entry was associated
                 */
                while (tmp < fg->group_status.entry_count) {
                        eid = (fg->entry_arr[tmp])->eid;
                        /* Get entry description structure. */
                        rv = _field_entry_get(unit, eid, _FP_ENTRY_PRIMARY, &f_ent);
                        if (BCM_FAILURE(rv)) {
                                FP_UNLOCK(fc);
                                return (rv);
                        }
                        
                        for (idx = 0; idx < _FP_POLICER_LEVEL_COUNT; idx++) {
                                f_ent_pl = f_ent->policer + idx;
                                if (f_ent_pl->pid == policer_id) {
                                        f_ent->flags |= _FP_ENTRY_DIRTY;
                                }
                        }
                        tmp++;
                }
        }

    

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_field_entry_policer_attach
 * Purpose:
 *      Attach a policer to a field entry.
 * Parameters:
 *      unit       - (IN) Unit number.
 *      entry_id   - (IN) Field entry ID.
 *      level      - (IN) Policer level.
 *      policer_id - (IN) Policer ID.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_entry_policer_attach(int unit, bcm_field_entry_t entry_id, 
                                   int level, bcm_policer_t policer_id)
{
    _field_entry_policer_t *f_ent_pl; /* Field entry policer structure.*/
    _field_control_t       *fc;       /* Field control structure.      */
    _field_policer_t       *f_pl;     /* Internal policer descriptor.  */
    _field_entry_t         *f_ent;    /* Internal entry descriptor.    */
    _field_stage_id_t      stage_id;  /* Pipeline stage id.            */
    int                    idx;       /* Entry policers iterator.      */
    int                    rv;        /* Operation return status.      */
    _field_stage_t         *stage_fc; /* Field stage control structure.*/
    _field_meter_pool_t    *f_mp;     /* Meter pool descriptor.        */

#if defined(BCM_KATANA_SUPPORT)
    vfp_policy_table_entry_t vfp_entry;
#endif

    /* Input parameters check. */
    if ((level >= _FP_POLICER_LEVEL_COUNT) || (level < 0)) {
        return (BCM_E_PARAM);
    }

    FIELD_IS_INIT(unit);
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    /* Get entry description structure. */
    rv = _field_entry_get(unit, entry_id, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get entry pipeline stage id. */
    stage_id = f_ent->group->stage_id;

#if defined(BCM_KATANA_SUPPORT)
    if (SOC_IS_KATANA(unit)) {
        if (_BCM_FIELD_STAGE_LOOKUP == stage_id) {
            rv = _bcm_esw_add_policer_to_table(unit, policer_id,
                                       VFP_POLICY_TABLEm, 0, &vfp_entry);
            if (BCM_FAILURE(rv)) {
                FP_UNLOCK(fc);
                return (rv);
            }
            if (f_ent->global_meter_policer.pid > 0) {
                _bcm_esw_policer_decrement_ref_count(unit, 
                                   f_ent->global_meter_policer.pid);
            }
            f_ent->global_meter_policer.pid = policer_id;
            f_ent->global_meter_policer.flags = level;
            /* Entry must be reinstalled for policer to take effect. */
            f_ent->flags  |= _FP_ENTRY_DIRTY;
            FP_UNLOCK(fc);
            return (BCM_E_NONE);
        }
    }
#endif
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
    /* Make sure stage has meters. */ 
    if (_BCM_FIELD_STAGE_LOOKUP == stage_id) {
        FP_UNLOCK(fc);
        return (BCM_E_UNAVAIL);
    }
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */

    /* Check if another  policer already attached at this level. */
    f_ent_pl = f_ent->policer + level;
    if (f_ent_pl->flags & _FP_POLICER_VALID) {
        FP_UNLOCK(fc);
        return (BCM_E_EXISTS);
    }

    /* Check if policer already attached to the entry. */
    for (idx = 0; idx < _FP_POLICER_LEVEL_COUNT; idx++) {
        f_ent_pl = f_ent->policer + idx;
        if (f_ent_pl->pid == policer_id) {
            FP_UNLOCK(fc);
            return (idx == level) ? (BCM_E_NONE) : (BCM_E_PARAM);
        }
    }

    /* Get policer description structure. */
    rv = _bcm_field_policer_get(unit, policer_id, &f_pl);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Check that policer can be shared. */
    if (f_pl->sw_ref_count > 1) {
        /* Policer sharing is restricted to a single stage. */
        if (stage_id != f_pl->stage_id) {
            FP_UNLOCK(fc);
            return (BCM_E_PARAM);
        }

        /* Policer sharing is restricted to a single level. */
        if (level != f_pl->level) {
            FP_UNLOCK(fc);
            return (BCM_E_PARAM);
        }

         /* Get meter pool stage control. */
        BCM_IF_ERROR_RETURN(_field_stage_control_get (unit, stage_id, &stage_fc));
        
        /* 
         * Check if entry's primary slice_number matches 
         * Policer meter pool slice_id for Level0 policer.
         */
        if (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
            if ((0 == level) && (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS)
                && _FP_INVALID_INDEX != f_pl->pool_index) {
                f_mp = stage_fc->meter_pool[f_pl->pool_index];
                if (f_ent->group->slices->slice_number != f_mp->slice_id) {
                    FP_UNLOCK(fc);
                    return (BCM_E_PARAM);
                }
            }
        }
    }

    /* Check policer mode support. */
    rv = _field_policer_mode_support(unit, f_ent, level, f_pl);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Increment policer reference counter. */
    f_pl->sw_ref_count++;

    /* Set policer stage. */
    f_pl->stage_id = stage_id;

    /* Set policer attachment level. */
    f_pl->level = level;

    /* Attach policer to an entry. */
    f_ent_pl = f_ent->policer + level;
    f_ent_pl->flags |= _FP_POLICER_VALID;
    f_ent_pl->pid    = policer_id;

    /* Entry must be reinstalled for policer to take effect. */
    f_ent->flags  |= _FP_ENTRY_DIRTY;

    /* Increment group meter count. */
    f_ent->group->group_status.meter_count++;

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_field_entry_policer_detach
 * Purpose:
 *      Detach a policer from a field entry.
 * Parameters:
 *      unit     - (IN) Unit number.
 *      entry_id - (IN) Field entry ID.
 *      level    - (IN) Policer level.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_entry_policer_detach(int unit, bcm_field_entry_t entry_id, 
                                   int level)
{
    _field_control_t       *fc;       /* Field control structure.      */
    _field_entry_t         *f_ent;    /* Internal entry descriptor.    */
    int                     rv;       /* Operation return status.      */

    /* Input parameters check. */
    if ((level >= _FP_POLICER_LEVEL_COUNT) || (level < 0)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get entry description structure. */
    rv = _field_entry_get(unit, entry_id, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = _field_entry_policer_detach(unit, f_ent, level);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_field_entry_policer_detach_all
 * Purpose:
 *      Detach all policers from a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry_id - (IN) Field entry ID.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_entry_policer_detach_all(int unit, bcm_field_entry_t entry_id)
{
    int       idx;                /* Entry policers iterator. */
    int       rv = BCM_E_NONE;    /* Operation return status. */

    /* Detach all the policers attached to an entry. */
    for (idx = 0; idx < _FP_POLICER_LEVEL_COUNT; idx++) {
        rv =  bcm_esw_field_entry_policer_detach(unit, entry_id, idx);
        if (BCM_E_EMPTY == rv) {
            /* No policer at this level. */
            rv = BCM_E_NONE;
        } else if (BCM_FAILURE(rv)) {
            break;
        }
    }
    return (rv);
}

/*
 * Function:
 *      bcm_field_entry_policer_get
 * Purpose:
 *      Get the policer(s) attached to a field entry.
 * Parameters:
 *      unit       - (IN) Unit number.
 *      entry_id   - (IN) Field entry ID.
 *      level      - (IN) Policer level.
 *      policer_id - (OUT) Policer ID.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_entry_policer_get(int unit, bcm_field_entry_t entry_id, 
                                int level, bcm_policer_t *policer_id)
{
    _field_entry_policer_t *f_ent_pl;/* Field entry policer structure.*/
    _field_entry_t         *f_ent;   /* Internal entry descriptor.    */
    _field_control_t       *fc;      /* Field control structure.      */
    int                    rv;       /* Operation return status.      */

    /* Input parameters check. */
    if ((level >= _FP_POLICER_LEVEL_COUNT) || (level < 0)) {
        return (BCM_E_PARAM);
    }

    if (NULL == policer_id) {
        return (BCM_E_PARAM);
    }

    FIELD_IS_INIT(unit);
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    /* Get entry description structure. */
    rv = _field_entry_get(unit, entry_id, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }
#if defined(BCM_KATANA_SUPPORT)
    if (SOC_IS_KATANA(unit)) {
        if (_BCM_FIELD_STAGE_LOOKUP == f_ent->group->stage_id) {
            if (f_ent->global_meter_policer.pid) {
                *policer_id = f_ent->global_meter_policer.pid;
                FP_UNLOCK(fc);
                return (rv);
            } 
            rv = (BCM_E_NOT_FOUND);
        }
    }
#endif

    f_ent_pl = f_ent->policer + level;
    /* Make sure policer attached to the entry. */
    if (0 == (f_ent_pl->flags & _FP_POLICER_VALID)) {
        rv = (BCM_E_NOT_FOUND);
    } else {
        *policer_id = f_ent_pl->pid;
    }

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_policer_create
 * Purpose:
 *      Create a policer entry.
 * Parameters:
 *      unit    - (IN) BCM device number.
 *      pol_cfg - (IN) Policer configuration.
 *      policer_id - (OUT) Policer ID.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_policer_create(int unit, bcm_policer_config_t *pol_cfg, 
                       bcm_policer_t *policer_id)
{
    _field_control_t    *fc;               /* Field control structure. */
        int                 rv;                /* Operation return status. */

    /* Input parameters check. */
    if (NULL == policer_id) {
        return (BCM_E_PARAM);
    }

    /* Reject unsupported flags. */
    if (pol_cfg->flags & BCM_POLICER_DROP_RED) {
        return (BCM_E_UNAVAIL);
    }

    FIELD_IS_INIT(unit);
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    rv = _field_policer_create(unit, pol_cfg, 0, policer_id);

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_policer_destroy
 * Purpose:
 *      Destroy a policer entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      policer_id - (IN) Policer ID.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_policer_destroy(int unit, bcm_policer_t policer_id)
{
    _field_control_t *fc;       /* Field control structure. */
    int               rv;       /* Operation return status. */

#ifdef BCM_KATANA_SUPPORT
    if (SOC_IS_KATANA(unit)) {
        int offset_mode=0;
        offset_mode = ((policer_id & BCM_POLICER_GLOBAL_METER_MODE_MASK) >>
                             BCM_POLICER_GLOBAL_METER_MODE_SHIFT);
        if (offset_mode) {   /* Global meter policer */
            rv = _bcm_esw_global_meter_policer_destroy(unit, policer_id); 
            return (rv);
        } 
    } 
#endif
    FIELD_IS_INIT(unit);
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);
    rv = _field_policer_destroy(unit, policer_id);
    FP_UNLOCK(fc);

    return (rv);
}

/*
 * Function:
 *      bcm_policer_destroy_all
 * Purpose:
 *      Destroy all policer entries.
 * Parameters:
 *      unit - (IN) Unit number.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_policer_destroy_all(int unit)
{
    _field_control_t *fc;              /* Field control structure.     */
    int              idx;              /* Policer hash iteration index.*/
    int              rv = BCM_E_NONE;  /* Operation return status.     */

    FIELD_IS_INIT(unit);
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    /* Iterate over all hash buckets. */
    for (idx = 0; idx < _FP_HASH_SZ(fc); idx++) {
        /* Destroy entries in each bucket. */
        while (NULL != fc->policer_hash[idx]) {
            rv = _field_policer_destroy2(unit, fc, fc->policer_hash[idx]);
            if (BCM_FAILURE(rv)) {
                break;
            }
        }
        if (BCM_FAILURE(rv)) {
            break;
        }
    }
    FP_UNLOCK(fc);
    
#ifdef BCM_KATANA_SUPPORT
    if (SOC_IS_KATANA(unit)) {
        rv = _bcm_esw_global_meter_policer_destroy_all(unit); 
    }
#endif
    return (rv);
}

/*
 * Function:
 *      bcm_policer_traverse
 * Purpose:
 *      Traverse all existing policer entries and call supplied
 *      callback function.
 * Parameters:
 *      unit - (IN) Unit number.
 *      cb - (IN) Callback function.
 *      user_data - (IN) User data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 *     To speed up traverse operation - no hw read is perfomed.
 */
int 
bcm_esw_policer_traverse(int unit, bcm_policer_traverse_cb cb, 
                         void *user_data)
{
    _field_control_t        *fc;      /* Field control structure.       */
    _field_policer_t        *f_pl;    /* Internal policer descriptor.   */
    bcm_policer_config_t    cfg;      /* Policer configuration.         */
    int                     idx;      /* Policer hash iteration index.  */
    int              rv = BCM_E_NONE; /* Operation return status.       */

    /* Input parameter check. */
    if (NULL == cb) {
        return (BCM_E_PARAM);
    } 

    FIELD_IS_INIT(unit);
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    /* Iterate over all hash buckets. */
    for (idx = 0; idx < _FP_HASH_SZ(fc); idx++) {
        /* Iterate over entries in each bucket. */
        f_pl = fc->policer_hash[idx]; 
        while (NULL != f_pl) {
            sal_memcpy(&cfg, &f_pl->cfg, sizeof(bcm_policer_config_t));
            rv = (*cb)(unit, f_pl->pid, &cfg, user_data);  
            if (BCM_FAILURE(rv)) {
                break;
            }
            f_pl = f_pl->next;
        }
        if (BCM_FAILURE(rv)) {
            break;
        }
    }
    FP_UNLOCK(fc);
#ifdef BCM_KATANA_SUPPORT
    if (SOC_IS_KATANA(unit)) {
        rv = _bcm_esw_global_meter_policer_traverse(unit,cb,user_data); 
    }
#endif
    return (rv);
}



/* Section: Field Meters */

/*
 * Function: bcm_esw_field_meter_create
 *
 * Description:
 *      Create a meter group and associate it with the entry.
 *
 * Parameters:
 *      unit - BCM device number
 *      entry - Entry ID
 *
 * Returns:
 *      BCM_E_XXX
 */

int
bcm_esw_field_meter_create(int unit,
                           bcm_field_entry_t entry)
{
    bcm_policer_config_t pol_cfg;        /* Policer configuration.     */
    int                  rv;             /* Operation return value.    */
    bcm_policer_t        policer_id = -1;/* Policer id.                */
    _field_control_t     *fc = NULL;     /* Field control structure.   */


    bcm_policer_config_t_init(&pol_cfg);

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc); 

    rv = _field_policer_create(unit, &pol_cfg, _FP_POLICER_INTERNAL,
                               &policer_id);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = bcm_esw_field_entry_policer_attach(unit, entry, 0, policer_id);
    if (BCM_FAILURE(rv)) {
        (void)_field_policer_destroy(unit, policer_id);
    }
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_meter_share
 *
 * Description:
 *     Share the meter pair from one entry with a second entry.
 *
 * Parameters:
 *      unit - BCM device number
 *      src_entry - Entry ID that has meter group
 *      dst_entry - Entry ID that will get meter group
 *
 * Returns:
 *      BCM_E_XXX
 */

int
bcm_esw_field_meter_share(int unit,
                          bcm_field_entry_t src_entry,
                          bcm_field_entry_t dst_entry)
{
    _field_control_t  *fc;          /* Field control structure. */
    bcm_policer_t     policer_id;   /* Policer id.              */
    int               rv;           /* Operation return status. */

    FIELD_IS_INIT(unit);

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    /* Read policer id from source entry. */
    rv = bcm_esw_field_entry_policer_get(unit, src_entry, 0, &policer_id);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Attach policer to a destination entry. */
    rv = bcm_esw_field_entry_policer_attach(unit, dst_entry, 0, policer_id);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function: bcm_esw_field_meter_destroy
 *
 * Description:
 *     Delete a meter associated with a entry.
 *
 * Parameters:
 *     unit  - BCM device number
 *     entry - Entry ID
 *
 * Returns:
 *     BCM_E_XXX
 *
 * Notes:
 *     The meter is only deallocated if no other entries are using it.
 */

int
bcm_esw_field_meter_destroy(int unit, bcm_field_entry_t entry)
{
    /* Detach level 0  policer from the entry. */
    return  bcm_esw_field_entry_policer_detach(unit, entry, 0);
}



/*
 * Function: bcm_esw_field_meter_set
 *
 * Description:
 *     Set the metering parameter.
 *
 * Parameters:
 *     unit        - BCM device number
 *     entry       - Entry ID
 *     meter_num   - Entry in meter group (BCM_FIELD_METER_xxx)
 *     kbits_sec   - Data rate to associate with meter (1000/sec)
 *     kbits_burst - Max burst to associate with meter (1000)
 *
 * Returns:
 *     BCM_E_XXX
 */

int
bcm_esw_field_meter_set(int unit,
                        bcm_field_entry_t entry,
                        int meter_num,
                        uint32 kbits_sec,
                        uint32 kbits_burst)
{

    bcm_policer_t     policer_id;   /* Policer id.                  */
    _field_policer_t  *f_pl;        /* Internal policer descriptor. */
    _field_entry_t    *f_ent;       /* Field entry structure.       */
    _field_control_t  *fc;          /* Field control structure.     */
    int               rv;           /* Operation return status.     */

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Read policer id from source entry. */
    rv = bcm_esw_field_entry_policer_get(unit, entry, 0, &policer_id);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Search the entry by eid. */
    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get policer reference count. */
    rv = _bcm_field_policer_get(unit, policer_id, &f_pl);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Invalid meter mode */
    if ((_BCM_FIELD_METER_BOTH & meter_num) == 0) {
        FP_ERR(("FP(unit %d) Error: invalid meter_num: %d.\n", unit, meter_num));
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }
  
    /* In Flow mode, check if the meter in the pair belongs to the entry */
    if (((f_pl->cfg.mode == bcmPolicerModeCommitted) && 
         (meter_num != BCM_FIELD_METER_COMMITTED)) ||
        ((f_pl->cfg.mode == bcmPolicerModePeak) && 
         (meter_num != BCM_FIELD_METER_PEAK))) {
        FP_ERR(("FP(unit %d) Error: Meter in Flow mode: invalid meter_num: %d.\n",
                unit, meter_num));
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }

    if (meter_num == BCM_FIELD_METER_PEAK) {
        f_pl->hw_flags    |= _FP_POLICER_PEAK_DIRTY; 
        f_pl->cfg.pkbits_sec   = kbits_sec;
        f_pl->cfg.pkbits_burst = kbits_burst;
    } else if (meter_num == BCM_FIELD_METER_COMMITTED) {
        f_pl->hw_flags  |= _FP_POLICER_COMMITTED_DIRTY; 
        f_pl->cfg.ckbits_sec   = kbits_sec;
        f_pl->cfg.ckbits_burst = kbits_burst;
    }

    f_ent->flags |= _FP_ENTRY_DIRTY; /* mark entry for update.  */

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: bcm_esw_field_meter_get
 *
 * Description:
 *     Get the metering parameter.
 *
 * Parameters:
 *      unit        - BCM device number
 *      entry       - Entry ID
 *      meter_num   - Choice of peak or committed meter values.
 *      kbits_sec   - (OUT) Data rate setting of meter (1000/sec)
 *      kbits_burst - (OUT) Max burst setting of meter (1000)
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_NOT_FOUND - Entry ID not found on unit.
 *     BCM_E_EMPTY     - No meter in entry
 *     BCM_E_PARAM     - 'kbits_sec' or 'kbits_burst' pointing to NULL
 *                       or bad 'meter_num' not selecting single meter.
 *     BCM_E_NONE      - Success
 */

int
bcm_esw_field_meter_get(int unit,
                        bcm_field_entry_t entry,
                        int meter_num,
                        uint32 *kbits_sec,
                        uint32 *kbits_burst)
{
    bcm_policer_t     policer_id;   /* Policer id.                  */
    _field_policer_t  *f_pl;        /* Internal policer descriptor. */
    _field_control_t  *fc;          /* Field control structure.     */
    int               rv;           /* Operation return status.     */


    if ((NULL == kbits_sec) || (NULL == kbits_burst))  {
        return (BCM_E_PARAM);
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    FP_LOCK(fc);

    /* Read policer id from source entry. */
    rv = bcm_esw_field_entry_policer_get(unit, entry, 0, &policer_id);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get policer reference count. */
    rv = _bcm_field_policer_get(unit, policer_id, &f_pl);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Invalid meter mode */
    if ((_BCM_FIELD_METER_BOTH & meter_num) == 0) {
        FP_ERR(("FP(unit %d) Error: invalid meter_num: %d.\n", unit, meter_num));
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }
  
    /* In Flow mode, check if the meter in the pair belongs to the entry */
    if (((f_pl->cfg.mode == bcmPolicerModeCommitted) && 
         (meter_num != BCM_FIELD_METER_COMMITTED)) ||
        ((f_pl->cfg.mode == bcmPolicerModePeak) && 
         (meter_num != BCM_FIELD_METER_PEAK))) {
        FP_ERR(("FP(unit %d) Error: Meter in Flow mode: invalid meter_num: %d.\n",
                unit, meter_num));
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }

    if (meter_num == BCM_FIELD_METER_COMMITTED) {
        *kbits_sec   = f_pl->cfg.ckbits_sec;
        *kbits_burst = f_pl->cfg.ckbits_burst;
    } else if (meter_num == BCM_FIELD_METER_PEAK) {
        *kbits_sec   = f_pl->cfg.pkbits_sec;
        *kbits_burst = f_pl->cfg.pkbits_burst;
    } else {
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
* Function: bcm_field_resync
*
* Purpose:
*     To invalidate HW FP entries that have not been replayed after warm boot.
*     Can be used in general to clear entries that are in HW but not in SW.
*
* Parameters:
*     unit     - BCM unit number
*
* Returns:
*     BCM_E_INIT      - Unit not initialized
*     BCM_E_NONE      - Success
*     BCM_E_XXX       - Other errors
*/
int
bcm_esw_field_resync(int unit)
{
    int               i, rv, tcam_idx, tcam_size;
    _field_control_t  *fc;
    _field_stage_t    *stage_fc;
    _field_slice_t    *fs;
    soc_mem_t         mem = INVALIDm;
    soc_field_t field = VALIDf;
    uint32            valid, e[SOC_MAX_MEM_FIELD_WORDS];
    int               slice_number = 0;
    int               slice_offset = 0;

    FIELD_IS_INIT(unit);

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));

    stage_fc = fc->stages;
    if (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
#ifdef BCM_FIREBOLT_SUPPORT
        if (SOC_IS_FBX(unit)) {
            mem = FP_TCAMm;
        }
#endif /* BCM_FIREBOLT_SUPPORT */

#ifdef BCM_EASYRIDER_SUPPORT
        if (SOC_IS_EASYRIDER(unit)) {
            mem = FP_INTERNALm;
            field = VALID_0f;
        }
#endif /* BCM_EASYRIDER_SUPPORT */
    } else {
    return BCM_E_UNAVAIL;
    }

    if (mem == INVALIDm) {
    return BCM_E_UNAVAIL;
    }

    FP_LOCK(fc);
    tcam_size = soc_mem_index_count(unit, mem);
    for (tcam_idx = 0; tcam_idx < tcam_size; tcam_idx++) {
        /* Read tcam entry. */
        sal_memset(e, 0, sizeof(uint32) * SOC_MAX_MEM_FIELD_WORDS);
        rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, tcam_idx, e);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return rv;
        }

        valid = soc_mem_field32_get(unit, mem, e, field);

        if (valid) {
            rv = _bcm_field_tcam_idx_to_slice_offset (unit, stage_fc, tcam_idx,
                                                      &slice_number,
                                                      &slice_offset);
            if (BCM_FAILURE(rv)) {
                FP_UNLOCK(fc);
                return rv;
            }
            fs = &stage_fc->slices[slice_number];
            for (i = 0; i < fs->entry_count; i++) {
                if (fs->entries[i] != NULL) {
                    if (!(fs->entries[i]->group->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) 
                        && fs->entries[i]->slice_idx == slice_offset) {
                        break;
                    } else if (fs->entries[i]->group->flags & 
                               _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
                        if ((fs->entries[i]->flags & _FP_ENTRY_SECOND_HALF) && 
                            fs->entries[i]->slice_idx == slice_offset
                            - fs->entry_count /                               \
                            ((stage_fc->flags & _FP_STAGE_HALF_SLICE) ? 1 : 2)) {
                            break;
                        } else if (!(fs->entries[i]->flags & _FP_ENTRY_SECOND_HALF) &&  
                                   fs->entries[i]->slice_idx == slice_offset) {
                            break;
                        }           
                    }
                }
            }
            if (i == fs->entry_count)
            {
                soc_mem_field32_set(unit, mem, e, field, 0);

                if (field == VALID_0f)
                {
                    soc_mem_field32_set(unit, mem, e, VALID_1f, 0);
                }

                rv = soc_mem_write(unit, mem, MEM_BLOCK_ANY, tcam_idx, e);
                if (BCM_FAILURE(rv)) {
                    FP_UNLOCK(fc);
                    return rv;
                }
            }
        }
    }
    FP_UNLOCK(fc);
    return BCM_E_NONE;
}

/*
 * Function:
 *      bcm_esw_field_data_qualifier_create
 * Purpose:
 *      Create an data/offset based qualifier.
 * Parameters:
 *      unit           - (IN) bcm device.
 *      data_qualifier - (IN) Qualifier descriptor:
 *                           such as packet type, byte offset, etc.
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_data_qualifier_create(int unit,  
                                 bcm_field_data_qualifier_t *data_qualifier)
{
    _field_control_t    *fc;     /* Field control structure.     */
    int                 rv;      /* Operation return status.     */

    /* Input parameters check. */
    if (NULL == data_qualifier) {
        return (BCM_E_PARAM);
    }

    /* Check data qualifier flags support */
    if ((0 == SOC_MEM_FIELD_VALID(unit, FP_UDF_OFFSETm,
                                  UDF1_ADD_GRE_OPTIONS0f)) &&
        (data_qualifier->flags &
         BCM_FIELD_DATA_QUALIFIER_OFFSET_GRE_OPTIONS_ADJUST)) {
        return (BCM_E_UNAVAIL);
    }
    if ((0 == SOC_MEM_FIELD_VALID(unit, FP_UDF_OFFSETm,
                                  UDF1_ADD_IPV4_OPTIONS0f)) &&
        (data_qualifier->flags &
         BCM_FIELD_DATA_QUALIFIER_OFFSET_IP4_OPTIONS_ADJUST)) {
        return (BCM_E_UNAVAIL);
    }
    if (data_qualifier->flags &
        BCM_FIELD_DATA_QUALIFIER_OFFSET_IP6_EXTENSIONS_ADJUST) {
        return (BCM_E_UNAVAIL);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_data_qualifier_create(unit, data_qualifier); 

    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_data_qualifier_multi_get
 *
 * Purpose:
 *      Return list of ids of defined data qualifiers, per standard API idiom.
 *
 * Parameters:
 *      unit       - (IN)  bcm device.
 *      qual_size  - (IN)  Size of given qualifier id array; if 0, indicates
 *                         return count of data qualifiers only.
 *      qual_array - (OUT) Base of array where to store returned data qualifier
 *                         ids.
 *      qual_count - (OUT) Number of qualifier ids stored in above array; if
 *                         qual_size was given as 0, then number of defined
 *                         qualifiers. 
 *
 * Returns:
 *      BCM_E_XXX
 */

int
bcm_esw_field_data_qualifier_multi_get(int unit, int qual_size, int *qual_array, int *qual_count)
{
    _field_control_t        *fc;
    _field_stage_t          *stage_fc;
    _field_data_control_t   *data_ctrl;
    _field_data_qualifier_t *f_dq;
    unsigned                dqcnt;

    /* Parameter checking */

    if (qual_count == NULL) {
        FP_ERR(("FP(unit %d) Error: qual_count == NULL.\n", unit));
        return (BCM_E_PARAM);
    }

    if (qual_size != 0 && qual_array == NULL) {
        FP_ERR(("FP(unit %d) Error: qual_array == NULL.\n", unit));
        return (BCM_E_PARAM);
    }

    /* Point to needed things */

    BCM_IF_ERROR_RETURN (_field_control_get(unit, &fc));
    BCM_IF_ERROR_RETURN(_field_stage_control_get(unit,
                                                 _BCM_FIELD_STAGE_INGRESS,
                                                 &stage_fc
                                                 )
                        );
    data_ctrl = stage_fc->data_ctrl;

    FP_LOCK(fc);

    /* Count defined data qualifiers */

    for (dqcnt = 0, f_dq = data_ctrl->data_qual;
         f_dq;
         f_dq = f_dq->next, ++dqcnt
         );

    if (qual_size == 0) {
        /* Return count of data qualifiers only */

        *qual_count = dqcnt;
    } else {
        /* Return array of data qualifier ids */ 

        if (qual_size > dqcnt) {
            qual_size = dqcnt;
        }
        
        *qual_count = qual_size;

        for (f_dq = data_ctrl->data_qual;
             qual_size != 0 && f_dq != NULL;
             --qual_size, f_dq = f_dq->next, ++qual_array
             ) {
            *qual_array = f_dq->qid;
        }
    }

    FP_UNLOCK(fc);

    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_data_qualifier_get
 *
 * Purpose:
 *      Return configuration of given data qualifier.
 *
 * Parameters:
 *      unit       - (IN)  bcm device.
 *      qual_id    - (IN)  Id of data qualifier.
 *      qual       - (OUT) Attributes of given data qualifier.
 *
 * Returns:
 *      BCM_E_XXX
 */

int
bcm_esw_field_data_qualifier_get(int unit, int qual_id, bcm_field_data_qualifier_t *qual)
{
    int                     rv;
    _field_control_t        *fc;
    _field_stage_t          *stage_fc;
    _field_data_qualifier_t *f_dq;

    /* Parameter checking */

    if (qual == NULL) {
        FP_ERR(("FP(unit %d) Error: qual == NULL.\n", unit));
        return (BCM_E_PARAM);
    }

    /* Point to needed things */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    BCM_IF_ERROR_RETURN(_field_stage_control_get(unit,
                                                 _BCM_FIELD_STAGE_INGRESS,
                                                 &stage_fc
                                                 )
                        );

    FP_LOCK(fc);
                        
    if ((rv = _bcm_field_data_qualifier_get(unit,
                                            stage_fc,
                                            qual_id,
                                            &f_dq
                                            )
         )
        == BCM_E_NONE
        ) {
        qual->qual_id     = f_dq->qid;
        qual->flags       = f_dq->flags;
        qual->offset_base = f_dq->offset_base;
        qual->offset      = f_dq->offset;
        qual->length      = f_dq->length;
    }

    FP_UNLOCK(fc);

    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_data_qualifier_destroy
 * Purpose:
 *      Destroy an data/offset based qualifier.
 * Parameters:
 *      unit     - (IN)  bcm device.
 *      qual_id  - (IN)  Data qualifier id.
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_data_qualifier_destroy(int unit, int qual_id)
{
    _field_control_t    *fc;     /* Field control structure.     */
    int                 rv;      /* Operation return status.     */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_data_qualifier_destroy(unit, qual_id); 

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_data_qualifier_destroy_all
 * Purpose:
 *      Delete all data/offset based qualifiers.
 * Parameters:
 *      unit          - (IN)  bcm device.
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_data_qualifier_destroy_all(int unit)
{
    _field_control_t    *fc;     /* Field control structure.     */
    int                 rv;      /* Operation return status.     */

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_data_qualifier_destroy_all(unit); 

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qset_data_qualifier_get
 * Purpose:
 *      Get field data qualifiers included in group qset. 
 * Parameters:
 *      unit          - (IN) bcm device.
 *      qset          - (IN) Group qualifier set.
 *      qual_max      - (IN) Maximum qualifiers to fill.
 *      qual_arr      - (OUT) Data qualifiers array.
 *      qual_count    - (OUT) Number of data qualifiers filled in qual_arr.
 * Returns:
 *      BCM_E_XXX
 */
int 
bcm_esw_field_qset_data_qualifier_get(int unit, bcm_field_qset_t *qset, int qual_max,
                                  int *qual_arr, int *qual_count) 
{
    _field_data_qualifier_p f_dq;  /* Field data qualifier iterator. */
    _field_control_t *fc;          /* Field control structure.       */
    _field_stage_t *stage_fc;      /* Stage field control structure. */
    bcm_field_qset_t  qset_temp;   /* Temporary qset copy.           */
    int count;                     /* Filled entries count.          */
    int rv;                        /* Operation return status.       */

    /* Input parameters check. */
    if ((qset == NULL) || (qual_max <= 0) || 
        (NULL == qual_arr) || (NULL == qual_count)) {
        return BCM_E_PARAM;
    }

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc); 
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Reset caller provided array. */
    sal_memset(qual_arr, 0, qual_max * sizeof(int));

    /* Copy qset to a temporary variable. */
    qset_temp = *qset;

    /* Fill caller array. */
    count = 0;
    f_dq = stage_fc->data_ctrl->data_qual; 

    /* Stage data qualifiers iteration array. */
    while (NULL != f_dq) {
        if (f_dq->hw_bmap & qset_temp.udf_map[0]) {
            /* Remove data qualifier udfs from the temporary qset. */
            qset_temp.udf_map[0] &= ~f_dq->hw_bmap;
            /* Add data qualifier id to caller array. */
            qual_arr[count] = f_dq->qid;
            count++;
            if (count >= qual_max) {
                break;
            }
        }
        f_dq = f_dq->next;
    }
    *qual_count = count;

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qset_data_qualifier_add
 * Purpose:
 *      Add field data qualifier to group qset.
 * Parameters:
 *      unit          - (IN) bcm device.
 *      qset          - (IN/OUT) Group qualifier set.
 *      qualifier_id  - (IN) Data qualifier id.
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_qset_data_qualifier_add(int unit, bcm_field_qset_t *qset,  
                                      int qual_id)
{
    _field_stage_t          *stage_fc;  /* Stage field control.       */
    _field_data_qualifier_t *f_dq;      /* Data qualifier descriptor. */
    _field_control_t        *fc;        /* Field control structure.   */
    int                     idx;        /* HW bitmap iteration index. */
    int                     rv;         /* Operation return status.   */
#ifdef BCM_TRIUMPH_SUPPORT
    uint32              reg_val;        /* Register value */
    uint32              ext_udf_support = 0; /* External UDF support status */
#endif

    /* Input parameters check. */
    if (NULL == qset) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc); 
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /*Get data qualifier info. */
    rv = _bcm_field_data_qualifier_get(unit, stage_fc, qual_id,  &f_dq);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

#ifdef BCM_TRIUMPH_SUPPORT
    if (SOC_IS_TRIUMPH(unit) || SOC_IS_TRIUMPH2(unit)) {
        rv = READ_ESM_KEYGEN_CTLr(unit, &reg_val);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
        ext_udf_support = soc_reg_field_get(unit, ESM_KEYGEN_CTLr, reg_val, 
                                            L2_ACL_PAYLOAD_MODEf);
    }
#endif

    for (idx = 0; idx <= stage_fc->data_ctrl->num_elems * 2; idx++) {
        if (f_dq->hw_bmap & (1 << idx)) {
            SHR_BITSET(qset->udf_map, idx);
            if (idx >= 0 && idx < stage_fc->data_ctrl->num_elems) {
                BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData0);
#ifdef BCM_TRIUMPH_SUPPORT
                /* External UDF support has to be enabled in ESM_KEYGEN_CTRLr*/
                if ((SOC_IS_TRIUMPH(unit) || SOC_IS_TRIUMPH2(unit)) && 
                    (1 == ext_udf_support)) {
                    if (SHR_BITGET(qset->udf_map, 0) && 
                        !SHR_BITGET(qset->udf_map, 1) &&
                        !SHR_BITGET(qset->udf_map, 3)) {
                        BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData2);
                    }
                } 
#endif /* !BCM_TRIUMPH_SUPPORT */
            } else if (idx >= stage_fc->data_ctrl->num_elems &&
                       idx < stage_fc->data_ctrl->num_elems * 2) {
                BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData1);
            }
        }
    }

#if defined(BCM_ENDURO_SUPPORT)
    if(SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit)) {
        /* See if not having to use all UDF1 */
        BCM_FIELD_QSET_REMOVE_INTERNAL(*qset, _bcmFieldQualifyData0);
        BCM_FIELD_QSET_REMOVE_INTERNAL(*qset, _bcmFieldQualifyData2);
        BCM_FIELD_QSET_REMOVE_INTERNAL(*qset, _bcmFieldQualifyData3);
        if (SHR_BITGET(qset->udf_map, 0) &&
            !SHR_BITGET(qset->udf_map, 1) &&
            SHR_BITGET(qset->udf_map, 2) && 
            !SHR_BITGET(qset->udf_map, 3)) {
            /* Add both UDF1_31_0 and UDF1_95_64 */
            BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData2);
            BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData3);
        } else if(SHR_BITGET(qset->udf_map, 0) &&
                  !SHR_BITGET(qset->udf_map, 1) && 
                  !SHR_BITGET(qset->udf_map, 2) && 
                  !SHR_BITGET(qset->udf_map, 3)){
                  /* Add UDF1_31_0 */
                  BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData2);
        } else if(!SHR_BITGET(qset->udf_map, 0) &&
                  !SHR_BITGET(qset->udf_map, 1) && 
                  SHR_BITGET(qset->udf_map, 2) && 
                  !SHR_BITGET(qset->udf_map, 3)){
                  /* Add UDF1_95_64 */
                  BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData3);
        } else {
            /* Add UDF1_127_0 */
            BCM_FIELD_QSET_ADD_INTERNAL(*qset, _bcmFieldQualifyData0);
        }
    }
#endif /* BCM_ENDURO_SUPPORT */

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}


/*
 * Function:
 *      bcm_esw_field_qualify_data
 * Purpose:
 *      Set data/mask in the search engine for entry field data qualifier.
 * Parameters:
 *      unit          - (IN) bcm device.
 *      eid           - (IN) Entry id. 
 *      qual_id       - (IN) Data qualifier id.
 *      data          - (IN) Match data.
 *      mask          - (IN) Match mask.
 *      length        - (IN) Length of data & mask arrays.
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_qualify_data(int unit, bcm_field_entry_t eid, int qual_id,
                           uint8 *data, uint8 *mask, uint16 length)
{
    _field_control_t        *fc;        /* Field control structure.   */
    int                     rv;         /* Operation return status.   */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_data(unit, eid, qual_id, data, mask, length);

    FP_UNLOCK(fc);
    return (rv);
}

#define _FP_L2_FORMAT_MIN   (0)
#define _FP_L2_FORMAT_MAX   (2)
/*
 * Function:
 *      bcm_esw_field_data_qualifier_ethertype_add
 * Purpose:
 *      Add ethertype based offset to data qualifier object.
 * Parameters:
 *      unit       - (IN) bcm device.
 *      qual_id    - (IN) Data qualifier id.
 *      etype      - (IN) Ethertype based offset specification.
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_data_qualifier_ethertype_add(int unit,  int qual_id,
                                 bcm_field_data_ethertype_t *etype)
{
    _field_control_t  *fc;             /* Field control structure.  */
    int               rv = BCM_E_NONE; /* Operation return status.  */

    /* Input parameters check. */
    if (NULL == etype) {
        return (BCM_E_PARAM);
    }

    /* Relative offset limited to multiples of 4 integers. */
    if (0 != etype->relative_offset % 4)  {
        return (BCM_E_UNAVAIL);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = fc->functions.fp_data_qualifier_ethertype_add(unit, qual_id, etype); 

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_data_qualifier_ethertype_delete
 * Purpose:
 *      Remove ethertype based offset from data qualifier object. 
 * Parameters:
 *      unit       - (IN) bcm device.
 *      qual_id    - (IN) Data qualifier id.
 *      etype      - (IN) Ethertype based offset specification.                 
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_data_qualifier_ethertype_delete(int unit, int qual_id,
                                 bcm_field_data_ethertype_t *etype)
{
    _field_control_t  *fc;             /* Field control structure.  */
    int               rv = BCM_E_NONE; /* Operation return status.  */

    /* Input parameters check. */
    if (NULL == etype) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = fc->functions.fp_data_qualifier_ethertype_delete(unit, qual_id, 
                                                          etype); 

    FP_UNLOCK(fc);
    return (rv);
}
#undef _FP_L2_FORMAT_MIN
#undef _FP_L2_FORMAT_MAX

/*
 * Function:
 *      bcm_esw_field_data_qualifier_ip_protocol_add
 * Purpose:
 *      Add ip protocol based offset to data qualifier object.
 * Parameters:
 *      unit        - (IN) bcm device.
 *      qual_id     - (IN) Data qualifier id.
 *      ip_protocol - (IN) Ethertype based offset specification.                 
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_data_qualifier_ip_protocol_add(int unit, int qual_id,
                                 bcm_field_data_ip_protocol_t *ip_protocol)
{
    _field_control_t  *fc;             /* Field control structure.  */
    int               rv = BCM_E_NONE; /* Operation return status.  */

    /* Input parameters check. */
    if (NULL == ip_protocol) {
        return (BCM_E_PARAM);
    }

    /* Relative offset limited to multiples of 4 integers. */
    if (0 != ip_protocol->relative_offset % 4)  {
        return (BCM_E_UNAVAIL);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);
    rv = fc->functions.fp_data_qualifier_ip_protocol_add(unit, qual_id, 
                                                         ip_protocol); 
    FP_UNLOCK(fc);
    return (rv);
}


/*
 * Function:
 *      bcm_esw_field_data_qualifier_ip_protocol_delete
 * Purpose:
 *      Remove ip protocol based offset from data qualifier object. 
 * Parameters:
 *      unit        - (IN) bcm device.
 *      qual_id     - (IN) Data qualifier id.
 *      ip_protocol - (IN) Ethertype based offset specification.                 
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_data_qualifier_ip_protocol_delete(int unit, int qual_id,
                                 bcm_field_data_ip_protocol_t *ip_protocol)
{
    _field_control_t  *fc;             /* Field control structure.  */
    int               rv = BCM_E_NONE; /* Operation return status.  */

    /* Input parameters check. */
    if (NULL == ip_protocol) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = fc->functions.fp_data_qualifier_ip_protocol_delete(unit, qual_id, 
                                                            ip_protocol); 
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_data_qualifier_packet_format_add
 * Purpose:
 *      Add packet format based offset to data qualifier object.
 * Parameters:
 *      unit          - (IN) bcm device.
 *      qual_id       - (IN) Data qualifier id.
 *      packet_format - (IN) Ethertype based offset specification.                 
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_data_qualifier_packet_format_add(int unit, int qual_id,
                                 bcm_field_data_packet_format_t *packet_format)
{
    _field_control_t          *fc;   /* Field control structure.  */
    int                       rv;    /* Operation return status.  */

    /* Input parameters check. */
    if (NULL == packet_format) {
        return (BCM_E_PARAM);
    }

    /* Relative offset calculation. */
    if (0 != packet_format->relative_offset % 4)  {
        return (BCM_E_UNAVAIL);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = fc->functions.fp_data_qualifier_packet_format_add(unit, qual_id, 
                                                           packet_format);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_data_qualifier_packet_format_delete
 * Purpose:
 *      Remove packet format based offset from data qualifier object. 
 * Parameters:
 *      unit           - (IN) bcm device.
 *      qual_id        - (IN) Data qualifier id.
 *      packet_format  - (IN) Ethertype based offset specification.                 
 * Returns:
 *      BCM_E_XXX
 */
int
bcm_esw_field_data_qualifier_packet_format_delete(int unit, int qual_id,
                                 bcm_field_data_packet_format_t *packet_format)
{
    _field_control_t           *fc;   /* Field control structure.  */
    int                        rv;    /* Operation return status.  */

    /* Input parameters check. */
    if (NULL == packet_format) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = fc->functions.fp_data_qualifier_packet_format_delete(unit, qual_id, 
                                                              packet_format);

    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_LoopbackType_get
 * Purpose:
 *      Get loopback type field qualification from a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      loopback_type - (OUT) Loopback type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_LoopbackType_get(int unit, 
                                       bcm_field_entry_t entry, 
                                       bcm_field_LoopbackType_t *loopback_type)
{
    uint8            data; /* HW data match criteria.  */
    uint8            mask; /* HW data mask.            */
    int              rv;   /* Operation return status. */

    /* Input parameters check. */
    if (NULL == loopback_type) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */
    rv = _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                          bcmFieldQualifyLoopbackType,
                                          &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    switch (data) {
      case 0x8:
          *loopback_type = bcmFieldLoopbackTypeAny;
          break;
      case 0x9:
          *loopback_type = bcmFieldLoopbackTypeRedirect;
          break;
      case 0xb:
          *loopback_type = bcmFieldLoopbackTypeMim;
          break;
      case 0xc:
#ifdef BCM_TRIDENT_SUPPORT
          if (SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) {
              *loopback_type = bcmFieldLoopbackTypeTrillNetwork;
          } else 
#endif /* BCM_TRIDENT_SUPPORT */
          {
              *loopback_type = bcmFieldLoopbackTypeWlan;
          }
          break;
#ifdef BCM_TRIDENT_SUPPORT
      case 0xd:
          if (SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) {
              *loopback_type = bcmFieldLoopbackTypeTrillAccess;
          } 
          break;
#endif /* BCM_TRIDENT_SUPPORT */
      case 0xe:
          {
              *loopback_type = bcmFieldLoopbackTypeMirror;
          }
          break;
      default:
          return (BCM_E_INTERNAL);
    }
    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_TunnelType_get
 * Purpose:
 *      Get tunnel type field qualification from a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      tunnel_type - (OUT) Tunnel type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TunnelType_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_TunnelType_t *tunnel_type)
{
    uint8            data; /* HW data match criteria.  */
    uint8            mask; /* HW data mask.            */
    int              rv;   /* Operation return status. */

    /* Input parameters check. */
    if (NULL == tunnel_type) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */
    rv = _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                          bcmFieldQualifyTunnelType,
                                          &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    switch (data) {
      case 0x1:
          *tunnel_type = bcmFieldTunnelTypeIp;
          break;
      case 0x2:
          *tunnel_type = bcmFieldTunnelTypeMpls;
          break;
      case 0x3:
          *tunnel_type = bcmFieldTunnelTypeMim;
          break;
      case 0x4:
          *tunnel_type = bcmFieldTunnelTypeWlanWtpToAc;
          break;
      case 0x5:
          *tunnel_type = bcmFieldTunnelTypeWlanAcToAc;
          break;
      case 0x6:
          *tunnel_type = bcmFieldTunnelTypeAutoMulticast;
          break;
      case 0x7:
          *tunnel_type = bcmFieldTunnelTypeTrill;
          break;
      default:
          return (BCM_E_INTERNAL);
    }
    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstL3Egress_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstL3Egress
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      if_id - (OUT) L3 forwarding object.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstL3Egress_get(int unit, bcm_field_entry_t entry, 
                                      bcm_if_t *if_id)
{
    int               rv = BCM_E_UNAVAIL;  /* Operation return status. */
#if defined(INCLUDE_L3)
    uint32            data; /* HW data match criteria.  */
    uint32            mask; /* HW data mask.            */

    /* Input parameters check. */
    if (NULL == if_id) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifyDstL3Egress,
                                           &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
        entry, bcmFieldQualifyDstL3Egress, &data, &mask));

    *if_id = data + BCM_XGS3_EGRESS_IDX_MIN;
#endif /* INCLUDE_L3 */
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMulticastGroup_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstMulticastGroup
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      group - (OUT) Multicast group id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMulticastGroup_get(int unit, 
                                            bcm_field_entry_t entry, 
                                            bcm_gport_t *group)
{
    uint32 data;   /* HW encoded qualifier data.  */
    uint32 mask;   /* HW encoding qualifier mask. */
    int rv;        /* Operation return status.    */
    uint8 mc_grptype_data; /* Multicast Group Type */

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                            bcmFieldQualifyDstMulticastGroup,
                                            &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    /* Get Multicast group type info */
    mc_grptype_data = (data >> ((SOC_IS_TD_TT(unit)) ? 16 : 14));

    BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
        entry, bcmFieldQualifyDstMulticastGroup, &data, &mask));

    if (_bcmFieldDestTypeL2mc == mc_grptype_data) {
        /* L2 MC */
        _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_L2, data);
    } else if (_bcmFieldDestTypeL3mc == mc_grptype_data)  {
        /* IPMC */
        _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_L3, data);
    } else {
        return (BCM_E_INTERNAL);
    }
    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMplsGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcMplsGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      mpls_port_id - (OUT) Mpls port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMplsGport_get(int unit, 
                                       bcm_field_entry_t entry,
                                       bcm_gport_t *mpls_port_id)
{
    uint32 data;   /* HW encoded qualifier data.  */
    uint32 mask;   /* HW encoding qualifier mask. */
    int rv;        /* Operation return status.    */

    /* Input parameters check. */
    if (NULL == mpls_port_id) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifySrcMplsGport,
                                           &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    data &=  0x1fff;
    BCM_GPORT_MPLS_PORT_ID_SET(*mpls_port_id, data);

    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMplsGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstMplsGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      mpls_port_id - (OUT) Mpls port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMplsGport_get(int unit, 
                                       bcm_field_entry_t entry, 
                                       bcm_gport_t *mpls_port_id)
{
    uint32 data;   /* HW encoded qualifier data.  */
    uint32 mask;   /* HW encoding qualifier mask. */
    int rv;        /* Operation return status.    */

    /* Input parameters check. */
    if (NULL == mpls_port_id) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                            bcmFieldQualifyDstMplsGport,
                                            &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
        entry, bcmFieldQualifyDstMplsGport, &data, &mask));

    BCM_GPORT_MPLS_PORT_ID_SET(*mpls_port_id, data);

    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMimGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcMimGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      mim_port_id - (OUT) Mim port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMimGport_get(int unit, 
                                      bcm_field_entry_t entry, 
                                      bcm_gport_t *mim_port_id)
{
    uint32 data;   /* HW encoded qualifier data.  */
    uint32 mask;   /* HW encoding qualifier mask. */
    int rv;        /* Operation return status.    */

    /* Input parameters check. */
    if (NULL == mim_port_id) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                            bcmFieldQualifySrcMimGport,
                                            &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    data &= 0x1fff;
    BCM_GPORT_MIM_PORT_ID_SET(*mim_port_id, data);

    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMimGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstMimGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      mim_port_id - (OUT) Mim port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMimGport_get(int unit, 
                                      bcm_field_entry_t entry, 
                                      bcm_gport_t *mim_port_id)
{
    uint32 data;   /* HW encoded qualifier data.  */
    uint32 mask;   /* HW encoding qualifier mask. */
    int rv;        /* Operation return status.    */

    /* Input parameters check. */
    if (NULL == mim_port_id) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                            bcmFieldQualifyDstMimGport,
                                            &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
        entry, bcmFieldQualifyDstMimGport, &data, &mask));

    BCM_GPORT_MIM_PORT_ID_SET(*mim_port_id, data);

    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcWlanGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcWlanGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      wlan_port_id - (OUT) Wlan port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcWlanGport_get(int unit, 
                                       bcm_field_entry_t entry, 
                                       bcm_gport_t *wlan_port_id)
{
    uint32 data;   /* HW encoded qualifier data.  */
    uint32 mask;   /* HW encoding qualifier mask. */
    int rv;        /* Operation return status.    */

    /* Input parameters check. */
    if (NULL == wlan_port_id) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifySrcWlanGport,
                                           &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    data &= 0x1fff;
    BCM_GPORT_WLAN_PORT_ID_SET(*wlan_port_id, data);

    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstWlanGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstWlanGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      wlan_port_id - (OUT) Wlan port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstWlanGport_get(int unit, 
                                       bcm_field_entry_t entry, 
                                       bcm_gport_t *wlan_port_id)
{
    uint32 data;   /* HW encoded qualifier data.  */
    uint32 mask;   /* HW encoding qualifier mask. */
    int rv;        /* Operation return status.    */

    /* Input parameters check. */
    if (NULL == wlan_port_id) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifyDstWlanGport,
                                           &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
        entry, bcmFieldQualifyDstWlanGport, &data, &mask));

    BCM_GPORT_WLAN_PORT_ID_SET(*wlan_port_id, data);

    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Loopback_get
 * Purpose:
 *      Get loopback field qualification from  a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      data - (OUT) Data to qualify with.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Loopback_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyLoopback,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InPort_get(int unit, bcm_field_entry_t entry, 
                                 bcm_port_t *data, bcm_port_t *mask)
{
    _field_control_t *fc;                 /* Field control structure.    */
    _field_entry_t   *f_ent;              /* Field entry structure.      */
    _field_group_t   *fg;                 /* Field group structure.      */
    int              rv;                  /* Operation return status.    */
    int              isGport;             /* Port format is gport.       */
#if defined(BCM_RAPTOR_SUPPORT) || defined (BCM_TRX_SUPPORT)
    bcm_port_t       port = 0;            /* Port iterator.              */
#endif /* BCM_RAPTOR_SUPPORT || BCM_TRX_SUPPORT */

    /* Check requested output format. */
    rv = bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport);
    BCM_IF_ERROR_RETURN(rv);

    /* Get field control structure. */
    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get field entry that contains InPort qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry,
                                   bcmFieldQualifyInPort, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }
    fg = f_ent->group;

#if defined(BCM_RAPTOR_SUPPORT) || defined (BCM_TRX_SUPPORT)
    if ((_BCM_FIELD_STAGE_INGRESS == fg->stage_id) && 
        (soc_feature(unit, soc_feature_field_ingress_ipbm))) {
        BCM_PBMP_ITER(f_ent->pbmp.data, port) {
            *data = *mask = port;
            break;
        }
    } else 
#endif /* BCM_RAPTOR_SUPPORT || BCM_TRX_SUPPORT */
    {
        /* Read qualifier match value and mask. */ 
        rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                              bcmFieldQualifyInPort,
                                              (uint32 *)data, (uint32 *)mask);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }
    }
    FP_UNLOCK(fc);

    if (isGport) {
        rv = bcm_esw_port_gport_get(unit, *data, data);
        BCM_IF_ERROR_RETURN(rv);
    } 
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_OutPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOutPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OutPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_port_t *data, 
    bcm_port_t *mask)
{
    int              rv;                  /* Operation return status.    */
    int              isGport;             /* Port format is gport.       */


    /* Check requested output format. */
    rv = bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport);
    BCM_IF_ERROR_RETURN(rv);

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifyOutPort,
                                           (uint32 *)data, (uint32 *)mask);
    BCM_IF_ERROR_RETURN(rv);

    if (isGport) {
        rv = bcm_esw_port_gport_get(unit, *data, data);
        BCM_IF_ERROR_RETURN(rv);
    } 
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InPorts_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInPorts
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InPorts_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_pbmp_t *data, 
    bcm_pbmp_t *mask)
{
    _field_control_t *fc;    /* Field control structure.    */
    uint32 hw_data;          /* HW encoded qualifier data.  */
    uint32 hw_mask;          /* HW encoding qualifier mask. */
    int rv;                  /* Operation return status.    */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

#if defined(BCM_RAPTOR_SUPPORT) || defined (BCM_TRX_SUPPORT)
    if (soc_feature(unit, soc_feature_field_ingress_ipbm)) {
        _field_entry_t *f_ent;

        rv = _bcm_field_entry_qual_get(unit, entry, 
                                       bcmFieldQualifyInPorts, &f_ent);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* Add data & mask to entry. */ 
        BCM_PBMP_ASSIGN(*data, f_ent->pbmp.data);
        BCM_PBMP_ASSIGN(*mask, f_ent->pbmp.mask);

        /* Remove loopback port from ipbm mask */
        if (soc_feature(unit, soc_feature_internal_loopback)) {
            BCM_PBMP_REMOVE(*mask, PBMP_LB(unit));                             
        }

        FP_UNLOCK(fc);
        return (BCM_E_NONE);
    }
#endif /* BCM_RAPTOR_SUPPORT || BCM_TRX_SUPPORT */

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifyInPorts,
                                           (uint32 *)&hw_data, 
                                           (uint32 *)&hw_mask);
    FP_UNLOCK(fc);
    BCM_IF_ERROR_RETURN(rv);

    SOC_PBMP_WORD_SET(*data, 0, hw_data);
    SOC_PBMP_WORD_SET(*mask, 0, hw_mask);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_OutPorts_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOutPorts
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OutPorts_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_pbmp_t *data, 
    bcm_pbmp_t *mask)
{
    _field_control_t *fc;    /* Field control structure.    */
    uint32 hw_data;          /* HW encoded qualifier data.  */
    uint32 hw_mask;          /* HW encoding qualifier mask. */
    int rv;                  /* Operation return status.    */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifyOutPorts,
                                           (uint32 *)&hw_data, 
                                           (uint32 *)&hw_mask);
    FP_UNLOCK(fc);
    BCM_IF_ERROR_RETURN(rv);

    SOC_PBMP_WORD_SET(*data, 0, hw_data);
    SOC_PBMP_WORD_SET(*mask, 0, hw_mask);
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Drop_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDrop
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Drop_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
#ifdef BCM_FIREBOLT2_SUPPORT
    /* 
     * FB2 has Drop at two places:
     *     one is FIXED (always used), and the other based on selectors. 
     */
    if (SOC_IS_FIREBOLT2(unit)) {
        _field_entry_t   *f_ent;
        _field_control_t *fc;
        int              rv;

        BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
        FP_LOCK(fc);

        rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
        if (BCM_FAILURE(rv)) {
            FP_UNLOCK(fc);
            return (rv);
        }

        /* Add data & mask to entry. */
        *data = f_ent->tcam.drop;
        *mask = f_ent->tcam.drop_mask;

        FP_UNLOCK(fc);
        return (BCM_E_NONE);
    }
#endif /* BCM_FIREBOLT2_SUPPORT */    

    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyDrop,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcModid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModid_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_module_t *data, 
    bcm_module_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                             bcmFieldQualifySrcModid,
                                             (uint32 *)data, (uint32 *)mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcPortTgid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcPortTgid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcPortTgid_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_port_t *data, 
    bcm_port_t *mask)
{
    return _field_qualify_PortTgid_get(unit, entry,
                        bcmFieldQualifySrcPortTgid, data, mask);

}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data_modid - (OUT) Qualifier module id.
 *      mask_modid - (OUT) Qualifier module id mask.
 *      data_port - (OUT) Qualifier port id.
 *      mask_port - (OUT) Qualifier port id mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_module_t *data_modid, 
    bcm_module_t *mask_modid, 
    bcm_port_t *data_port, 
    bcm_port_t *mask_port)
{
    _field_control_t *fc;    /* Field control structure.    */
    int isGport;             /* Port format is gport.       */
    int isLocal;             /* Local module id flag.       */
    int rv;                  /* Operation return status.    */

    /* Input parameters check. */
    if ((NULL == data_port) || (NULL == mask_port) ||
        (NULL == data_modid) || (NULL == mask_modid)) {
        return (BCM_E_PARAM);
    }


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_Port_get(unit, entry,
                                 data_modid, mask_modid,
                                 data_port,  mask_port,
                                 bcmFieldQualifySrcPort);
    FP_UNLOCK(fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Check requested output format. */
    rv = bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport);
    BCM_IF_ERROR_RETURN(rv);

    if (isGport) {
        BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit,
            BCM_STK_MODMAP_GET, *data_modid, *data_port, data_modid, data_port));
        BCM_GPORT_MODPORT_SET(*data_port, *data_modid, *data_port);
        *mask_port = BCM_FIELD_EXACT_MATCH_MASK;
    } else {
        if ((NUM_MODID(unit) > 1) && (SOC_IS_TR_VL(unit)) ) {
            rv = _bcm_esw_modid_is_local(unit, *data_modid, &isLocal);
            BCM_IF_ERROR_RETURN(rv);
            if (isLocal) {
                (*data_modid) += ((*data_port) / 32);
                *data_port = (*data_port) % 32;
            }
            *mask_port = BCM_FIELD_EXACT_MATCH_MASK;
            *mask_modid = BCM_FIELD_EXACT_MATCH_MASK;
        }
    }
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcTrunk_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcTrunk
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcTrunk_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_trunk_t *data, 
    bcm_trunk_t *mask)
{
    _field_control_t *fc;    /* Field control structure.    */
    int isGport;             /* Port format is gport.       */
    int rv;                  /* Operation return status.    */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_Trunk_get(unit, entry, data, mask, 
                                  bcmFieldQualifySrcTrunk);

    FP_UNLOCK(fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Check requested output format. */
    rv = bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport);
    BCM_IF_ERROR_RETURN(rv);

    if (isGport) {
        BCM_GPORT_TRUNK_SET(*data, *data);
        *mask = BCM_FIELD_EXACT_MATCH_MASK;
    }
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstModid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstModid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstModid_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_module_t *data, 
    bcm_module_t *mask)
{

    if (NULL == data || NULL == mask) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    BCM_IF_ERROR_RETURN(_bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                             bcmFieldQualifyDstModid,
                                             (uint32 *)data, (uint32 *)mask));

    /* clear destination type bits set internally */
    BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
        entry, bcmFieldQualifyDstModid, (uint32 *)data, (uint32 *)mask));

    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstPortTgid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstPortTgid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstPortTgid_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_port_t *data, 
    bcm_port_t *mask)
{
    return _field_qualify_PortTgid_get(unit, entry,
                                       bcmFieldQualifyDstPortTgid, 
                                       data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data_modid - (OUT) Qualifier module id.
 *      mask_modid - (OUT) Qualifier module id mask.
 *      data_port - (OUT) Qualifier port id.
 *      mask_port - (OUT) Qualifier port id mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_module_t *data_modid, 
    bcm_module_t *mask_modid, 
    bcm_port_t *data_port, 
    bcm_port_t *mask_port)
{
    _field_control_t *fc;    /* Field control structure.    */
    int isGport;             /* Port format is gport.       */
    int isLocal;             /* Local module id flag.       */
    int rv;                  /* Operation return status.    */

    /* Input parameters check. */
    if ((NULL == data_port) || (NULL == mask_port) ||
        (NULL == data_modid) || (NULL == mask_modid)) {
        return (BCM_E_PARAM);
    }


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_Port_get(unit, entry,
                                 data_modid, mask_modid,
                                 data_port,  mask_port,
                                 bcmFieldQualifyDstPort);
    FP_UNLOCK(fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Check requested output format. */
    rv = bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport);
    BCM_IF_ERROR_RETURN(rv);

    if (isGport) {
        BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit,
            BCM_STK_MODMAP_GET, *data_modid, *data_port, data_modid, data_port));
        BCM_GPORT_MODPORT_SET(*data_port, *data_modid, *data_port);
        *mask_port = BCM_FIELD_EXACT_MATCH_MASK;
    } else {
        if ((NUM_MODID(unit) > 1) && (SOC_IS_TR_VL(unit)) ) {
            rv = _bcm_esw_modid_is_local(unit, *data_modid, &isLocal);
            BCM_IF_ERROR_RETURN(rv);
            if (isLocal) {
                (*data_modid) += ((*data_port) / 32);
                *data_port = (*data_port) % 32;
            }
            *mask_port = BCM_FIELD_EXACT_MATCH_MASK;
            *mask_modid = BCM_FIELD_EXACT_MATCH_MASK;
        }
    }
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstTrunk_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstTrunk
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstTrunk_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_trunk_t *data, 
    bcm_trunk_t *mask)
{
    _field_control_t *fc;    /* Field control structure.    */
    int isGport;             /* Port format is gport.       */
    int rv;                  /* Operation return status.    */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_Trunk_get(unit, entry, data, mask, 
                                  bcmFieldQualifyDstTrunk);

    FP_UNLOCK(fc);
    BCM_IF_ERROR_RETURN(rv);

    /* Check requested output format. */
    rv = bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport);
    BCM_IF_ERROR_RETURN(rv);

    if (isGport) {
        BCM_GPORT_TRUNK_SET(*data, *data);
        *mask = BCM_FIELD_EXACT_MATCH_MASK;
    }
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerL4SrcPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerL4SrcPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerL4SrcPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_l4_port_t *data, 
    bcm_l4_port_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                             bcmFieldQualifyInnerL4SrcPort,
                                             (uint32 *)data, (uint32 *)mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerL4DstPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerL4DstPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerL4DstPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_l4_port_t *data, 
    bcm_l4_port_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                             bcmFieldQualifyInnerL4DstPort,
                                             (uint32 *)data, (uint32 *)mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L4SrcPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL4SrcPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L4SrcPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_l4_port_t *data, 
    bcm_l4_port_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                             bcmFieldQualifyL4SrcPort,
                                             (uint32 *)data, (uint32 *)mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L4DstPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL4DstPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L4DstPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_l4_port_t *data, 
    bcm_l4_port_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                             bcmFieldQualifyL4DstPort,
                                             (uint32 *)data, (uint32 *)mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlan_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOuterVlan
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlan_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    int     rv;       /* Operation return status. */
    uint8  hw_data;  /* Installed entry value.   */
    uint8  hw_mask;  /* Installed entry mask.    */


    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    rv = bcm_esw_field_qualify_OuterVlanId_get(unit, entry, 
                                               data, mask);
    BCM_IF_ERROR_RETURN(rv);

    rv = bcm_esw_field_qualify_OuterVlanCfi_get(unit, entry,
                                                &hw_data, &hw_mask); 
    BCM_IF_ERROR_RETURN(rv);
    *data |= (hw_data << 12);
    *mask |= (hw_mask << 12);

    rv = bcm_esw_field_qualify_OuterVlanPri_get(unit, entry,
                                                &hw_data, &hw_mask);
    BCM_IF_ERROR_RETURN(rv);
    *data |= (hw_data << 13);
    *mask |= (hw_mask << 13);
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlan_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerVlan
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlan_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    uint8  hw_data;  /* Installed entry value.   */
    uint8  hw_mask;  /* Installed entry mask.    */
    int    rv;       /* Operation return status. */


    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    rv = bcm_esw_field_qualify_InnerVlanId_get(unit, entry, 
                                               data, mask);
    BCM_IF_ERROR_RETURN(rv);

    rv = bcm_esw_field_qualify_InnerVlanCfi_get(unit, entry,
                                                &hw_data, &hw_mask); 
    BCM_IF_ERROR_RETURN(rv);
    *data |= (hw_data << 12);
    *mask |= (hw_mask << 12);

    rv = bcm_esw_field_qualify_InnerVlanPri_get(unit, entry,
                                                 &hw_data, &hw_mask);
    BCM_IF_ERROR_RETURN(rv);
    *data |= (hw_data << 13);
    *mask |= (hw_mask << 13);
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_EtherType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyEtherType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_EtherType_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *data, 
    uint16 *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint16_get(unit, entry, 
                                             bcmFieldQualifyEtherType,
                                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_EqualL4Port_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyEqualL4Port
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      flag - (OUT) Qualifier flags.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_EqualL4Port_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *flag)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpProtocol_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpProtocol
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpProtocol_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyIpProtocol,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpInfo_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpInfo
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpInfo_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    int  rv;           /* Operation return status. */

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifyIpInfo,
                                           data, mask);

#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAPTOR_SUPPORT) || defined(BCM_TRX_SUPPORT)
    if (SOC_IS_FIREBOLT2(unit) || SOC_IS_RAVEN(unit) || \
        SOC_IS_TRX(unit) || SOC_IS_HAWKEYE(unit)) {
        /* In FB2 More fragments bit replaced with whole packet bit. */
        *data = ((*data & BCM_FIELD_IP_HDR_OFFSET_ZERO) | 
                 (*data & BCM_FIELD_IP_CHECKSUM_OK) | 
                 (*data ^ BCM_FIELD_IP_HDR_FLAGS_MF));
    }
#endif /* BCM_FIREBOLT_SUPPORT || BCM_RAPTOR_SUPPORT || BCM_TRX_SUPPORT */

    return (BCM_E_NONE); 
}

/*
 * Function:
 *      bcm_esw_field_qualify_PacketRes_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyPacketRes
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_PacketRes_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    int  rv;            /* Operation return status. */

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifyPacketRes,
                                           data, mask);
    BCM_IF_ERROR_RETURN(rv);

    if (SOC_IS_EASYRIDER(unit) &&
        soc_feature(unit, soc_feature_field_pkt_res_adj))
    {
        (*data)++;
    }

    /* Translate data #defines to hardware encodings */
    switch (*data) {
    case 0x0:
        *data = BCM_FIELD_PKT_RES_UNKNOWN;
        break;
    case 0x1:
        *data = BCM_FIELD_PKT_RES_CONTROL;
        break;
    case 0x2:
        *data = BCM_FIELD_PKT_RES_BPDU;
        break;
    case 0x3:
        *data = BCM_FIELD_PKT_RES_L2BC;
        break;
    case 0x4:
        *data = BCM_FIELD_PKT_RES_L2UC;
        break;
    case 0x5:
        *data = BCM_FIELD_PKT_RES_L2UNKNOWN;
        break;
    case 0x6:
        *data = BCM_FIELD_PKT_RES_L3MCUNKNOWN;
        break;
    case 0x7:
        *data = BCM_FIELD_PKT_RES_L3MCKNOWN;
        break;
    case 0x8:
        *data = BCM_FIELD_PKT_RES_L2MCKNOWN;
        break;
    case 0x9:
        *data = BCM_FIELD_PKT_RES_L2MCUNKNOWN;
        break;
    case 0xa:
        *data = BCM_FIELD_PKT_RES_L3UCKNOWN;
        break;
    case 0xb: 
        *data = BCM_FIELD_PKT_RES_L3UCUNKNOWN;
        break;
    case 0xc: 
        *data = BCM_FIELD_PKT_RES_MPLSKNOWN;
        break;
    case 0xd: 
        *data = BCM_FIELD_PKT_RES_MPLSL3KNOWN;
        break;
    case 0xe: 
        *data = BCM_FIELD_PKT_RES_MPLSL2KNOWN;
        break;
    case 0xf: 
        *data = BCM_FIELD_PKT_RES_MPLSUNKNOWN;
        break;
    default:
        return (BCM_E_INTERNAL);
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip_t *data, 
    bcm_ip_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                              bcmFieldQualifySrcIp,
                                              data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip_t *data, 
    bcm_ip_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                              bcmFieldQualifyDstIp,
                                              data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Tos_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTos
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Tos_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return  _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                             bcmFieldQualifyTos,
                                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DSCP_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDSCP
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DSCP_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return  _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                             bcmFieldQualifyDSCP,
                                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpFlags_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpFlags
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpFlags_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return  _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                             bcmFieldQualifyIpFlags,
                                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_TcpControl_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTcpControl
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TcpControl_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return  _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                              bcmFieldQualifyTcpControl,
                                              data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_TcpSequenceZero_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTcpSequenceZero
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      flag - (OUT) Qualifier match flags.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TcpSequenceZero_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *flag)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_TcpHeaderSize_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTcpHeaderSize
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TcpHeaderSize_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ttl_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTtl
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ttl_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    _field_control_t *fc;
    int              rv;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

#if defined(BCM_FIREBOLT2_SUPPORT)
    if (SOC_IS_FIREBOLT2(unit)) {
        rv =  _bcm_field_fb2_qualify_ttl_get(unit, entry, data, mask);     
    } else 
#endif /* BCM_FIREBOLT2_SUPPORT */
        
#if defined(BCM_RAPTOR_SUPPORT)
    if (SOC_IS_RAVEN(unit) || SOC_IS_HAWKEYE(unit)) {
        rv =  _bcm_field_raven_qualify_ttl_get(unit, entry, data, mask);     
    } else 
#endif /* BCM_RAPTOR_SUPPORT */
    {
        /* Read qualifier match value and mask. */
        rv = _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                              bcmFieldQualifyTtl,
                                              data, mask);
    }
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_RangeCheck_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyRangeCheck
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      max_count - (IN) Max entries to fill.
 *      range - (OUT) Range checkers array.
 *      invert - (OUT) Range checkers invert array.
 *      count - (OUT) Number of filled range checkers.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_RangeCheck_get(
    int unit, 
    bcm_field_entry_t entry, 
    int max_count, 
    bcm_field_range_t *range, 
    int *invert, 
    int *count)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_stage_t           *stage_fc;
    _field_entry_t           *f_ent;
    _bcm_field_qual_data_t   data;
    _bcm_field_qual_data_t   mask;
    _field_control_t         *fc;
    _field_range_t           *fr;
    int                      idx;
    int                      rv;


    /* Input parameters check. */
    if (NULL == count) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    /* Get field entry part that contains qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, bcmFieldQualifyRangeCheck, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return rv;
    }

    if (NULL == f_ent->group) {
        FP_UNLOCK(fc);
        return (BCM_E_INTERNAL);
    }

    /* Get stage field control structure. */
    rv = _field_stage_control_get(unit, f_ent->group->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, bcmFieldQualifyRangeCheck, &q_offset);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Read qualifier match value and mask. */
    rv = _bcm_field_qual_value_get(unit, q_offset, f_ent, data, mask);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Fill range indexes. */
    idx = 0;
    for (fr = stage_fc->ranges; fr != NULL; fr = fr->next) {
        if (mask[0] & (1 <<  fr->hw_index)) {
            if (idx >=  max_count) {
                idx++;
                continue;
            }
            if (NULL != range) {
                range[idx] = fr->rid;
            }
            if (NULL != invert) {
                if (data[0] & (1 << fr->hw_index)) {
                    invert[idx] = FALSE;
                } else {
                    invert[idx] = TRUE;
                }
            }
            idx++;
        }
    }
    *count = idx;
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIp6_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIp6
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIp6_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifySrcIp6,
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstIp6_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstIp6
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstIp6_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifyDstIp6, 
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIp6High_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIp6High
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIp6High_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifySrcIp6High,
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIp6Low_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIp6Low
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIp6Low_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifySrcIp6Low,
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstIp6Low_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstIp6Low
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstIp6Low_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifyDstIp6Low,
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIpEqualDstIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIpEqualDstIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      flag - (OUT) Qualifier match flags.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIpEqualDstIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *flag)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstIp6High_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstIp6High
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstIp6High_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifyDstIp6High,
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ip6NextHeader_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIp6NextHeader
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ip6NextHeader_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyIp6NextHeader,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ip6TrafficClass_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIp6TrafficClass
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ip6TrafficClass_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyIp6TrafficClass,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIp6FlowLabel_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIp6FlowLabel
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIp6FlowLabel_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifyInnerIp6FlowLabel,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ip6FlowLabel_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIp6FlowLabel
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ip6FlowLabel_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                                 bcmFieldQualifyIp6FlowLabel,
                                                 data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ip6HopLimit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIp6HopLimit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ip6HopLimit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return bcm_esw_field_qualify_Ttl_get(unit, entry, data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMac_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcMac
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMac_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_mac_t *data, 
    bcm_mac_t *mask)
{
    return _field_qualify_macaddr_get(unit, entry,
                                      bcmFieldQualifySrcMac, 
                                      data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMac_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstMac
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMac_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_mac_t *data, 
    bcm_mac_t *mask)
{
    return _field_qualify_macaddr_get(unit, entry,
                                      bcmFieldQualifyDstMac, 
                                      data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_PacketFormat_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyPacketFormat
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_PacketFormat_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    bcm_field_IpType_t     iptype;         /* QualifyIptype value.    */
    bcm_field_L2Format_t   l2_fmt;         /* QualifyL2Format value.  */
    _field_control_t       *fc;            /* Field control structure.*/
    uint8                  hw_data;        /* Hardware data.          */        
    uint8                  hw_mask;        /* Hardware mask.          */        
    int                    rv;             /* Operation return status.*/


    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }
    *data = *mask = 0;


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = bcm_esw_field_qualify_L2Format_get(unit, entry, &l2_fmt);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Translate #defines for lower 2 bits into HW values. */
    switch (l2_fmt) {
      case bcmFieldL2FormatEthII: 
          *data |= BCM_FIELD_PKT_FMT_L2_ETH_II; 
          *mask |= BCM_FIELD_PKT_FMT_L2_ETH_II; 
          break;
      case bcmFieldL2FormatAny: 
          break;
      case bcmFieldL2FormatSnap:
          *data |= BCM_FIELD_PKT_FMT_L2_SNAP; 
          *mask |= BCM_FIELD_PKT_FMT_L2_SNAP; 
          break;
      case bcmFieldL2FormatLlc:
          *data |= BCM_FIELD_PKT_FMT_L2_LLC; 
          *mask |= BCM_FIELD_PKT_FMT_L2_LLC; 
          break;
      default:
          FP_UNLOCK(fc);
          return (BCM_E_INTERNAL);
    }

    rv = bcm_esw_field_qualify_VlanFormat_get(unit, entry, &hw_data, &hw_mask);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    if (hw_mask != 0) {
        if (hw_mask & BCM_FIELD_VLAN_FORMAT_INNER_TAGGED) {
            *mask |= BCM_FIELD_PKT_FMT_INNER_TAGGED;
            *data = hw_data & BCM_FIELD_VLAN_FORMAT_INNER_TAGGED;
        }
        if (hw_mask & BCM_FIELD_VLAN_FORMAT_OUTER_TAGGED) {
            *mask |= BCM_FIELD_PKT_FMT_OUTER_TAGGED;
            *data = hw_data & BCM_FIELD_VLAN_FORMAT_OUTER_TAGGED;
        }
    }

    rv = bcm_esw_field_qualify_IpType_get(unit, entry, &iptype);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    switch (iptype) {
      case bcmFieldIpTypeAny: 
          break;
      case bcmFieldIpTypeIpv4Any: 
          *data |= BCM_FIELD_PKT_FMT_IPV4; 
          *mask |= BCM_FIELD_PKT_FMT_IPV4; 
          break;
      case bcmFieldIpTypeIpv6: 
          *data |= BCM_FIELD_PKT_FMT_IPV6; 
          *mask |= BCM_FIELD_PKT_FMT_IPV6; 
          break;
      case bcmFieldIpTypeIpv6Not: 
          *mask |= BCM_FIELD_PKT_FMT_IPV6; 
          break;
      case bcmFieldIpTypeIpv4Not: 
          *mask |= BCM_FIELD_PKT_FMT_IPV4; 
          break;
      case bcmFieldIpTypeNonIp: 
          *mask |= BCM_FIELD_PKT_FMT_IPV4; 
          *mask |= BCM_FIELD_PKT_FMT_IPV6; 
          break;
      default:
          FP_UNLOCK(fc);
          return (BCM_E_INTERNAL);
    }

    FP_UNLOCK(fc);
    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMacGroup_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcMacGroup
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMacGroup_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                                 bcmFieldQualifySrcMacGroup,
                                                 data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIpType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIpType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      type - (OUT) Inner ip header ip type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIpType_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpType_t *type)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_ForwardingType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyForwardingType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      type - (OUT) Qualifier match forwarding type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ForwardingType_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_ForwardingType_t *type)
{
    int                 rv;     /* Operation return structure. */
    uint32              data;   /* HW qualifier value.         */
    uint32              mask;   /* HW qualifier mask.          */

    /* Input parameters check. */
    if (NULL == type) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifyForwardingType,
                             &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    if ((0 == data) && (mask == 0)) {
        *type = bcmFieldForwardingTypeAny;
    } else if ((0 == data) && (mask == 6)) {
        *type = bcmFieldForwardingTypeL2;
    } else if ((0 == data) && (mask == 7)) {
        *type = bcmFieldForwardingTypeL2Independent;
    } else if ((1 == data) && (mask == 7)) {
        *type = bcmFieldForwardingTypeL2Shared;
    } else if ((2 == data) && (mask == 7)) {
        *type =  bcmFieldForwardingTypeL2Vpn;
    } else if ((3 == data) && (mask == 7)) {
        *type = bcmFieldForwardingTypeL2VpnDirect;
    } else if ((4 == data) && (mask == 7)) {
        *type = bcmFieldForwardingTypeL3Direct;
    } else if ((5 == data) && (mask == 7)) {
        *type = bcmFieldForwardingTypeL3;
    } else {
        return (BCM_E_INTERNAL);
    }
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      type - (OUT) Qualifier match ip type.
 * Returns: *      BCM_E_XXX * Notes: */
int 
bcm_esw_field_qualify_IpType_get(int unit, 
                                 bcm_field_entry_t entry, 
                                 bcm_field_IpType_t *type)
{
    _field_entry_t      *f_ent;  /* Field entry structure.   */
    _field_control_t    *fc;     /* Field control structure. */
    int                 rv;      /* Operation return status. */

    if (NULL == type) {
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = fc->functions.fp_qualify_ip_type_get(unit, f_ent, type);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2Format_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2Format
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      type - (OUT) Qualifier match l2 format.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2Format_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_L2Format_t *type)
{
    int       rv;     /* Operation return structure. */
    uint32    data;   /* HW qualifier value.         */
    uint32    mask;   /* HW qualifier mask.          */

    /* Input parameters check. */
    if (NULL == type) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifyL2Format,
                             &data, &mask);
    if ((0 == data) && (mask == 0)) {
        *type = bcmFieldL2FormatAny;
    } else if ((0 == data) && (mask == 3)) {
        *type = bcmFieldL2FormatEthII;
    } else if ((1 == data) && (mask == 3)) {
        *type = bcmFieldL2FormatSnap;
    } else if ((2 == data) && (mask == 7)) {
        *type = bcmFieldL2FormatLlc;
    } else {
        return (BCM_E_INTERNAL);
    }
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_VlanFormat_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyVlanFormat
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_VlanFormat_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    _field_control_t *fc;       /* Field control structure. */
    int              rv;        /* Operation return status. */


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_VlanFormat_get(unit, entry, 
                                          bcmFieldQualifyVlanFormat,
                                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_MHOpcode_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyMHOpcode
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_MHOpcode_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return  _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                             bcmFieldQualifyMHOpcode,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_UserDefined_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyUserDefined
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      udf_id - (IN) Udf spec id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_UserDefined_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_udf_t udf_id, 
    uint8 data[BCM_FIELD_USER_FIELD_SIZE], 
    uint8 mask[BCM_FIELD_USER_FIELD_SIZE])
{
    _bcm_field_qual_offset_t *q_offset;     /* Data qualifier offset in tcam. */
    _bcm_field_qual_offset_t q_offset_temp; /* Data qualifier offset in tcam. */
    uint32                   data_word;     /* Data qualifier match key value.*/
    uint32                   mask_word;     /* Data qualifier match key mask. */
    int                      f2_idx;        /* Temporary index.               */
    _field_control_t         *fc;           /* Field control structure.       */
    _field_group_t           *fg    = NULL; /* Field entry group structure.   */
    _field_stage_t           *stage_fc;
    _field_entry_t           *f_ent = NULL; /* Field entry structure.         */
    int                      qid = 0;       /* Data qualifier id.             */
    int                      rv;            /* Operation return status.       */
    int                      idx;


    /* Range check udf_id and confirm non-null pointers */
    if (udf_id >=BCM_FIELD_USER_NUM_UDFS ||
        data == NULL ||
        mask == NULL) {
        FP_ERR(("FP(unit %d) Error: udf_id=%d out-of-range or "
                "data==NULL || mask==NULL\n", unit, udf_id));
        return (BCM_E_PARAM);
    }

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    fg = f_ent->group;

    if (!SHR_BITGET(fg->qset.udf_map, udf_id)) { 
        FP_ERR(("FP(unit %d) Error: udf_id %d not in group=%d Qset\n",
                unit, udf_id, fg->gid));
        FP_UNLOCK(fc);
        return (BCM_E_PARAM);
    }


    switch (fc->udf[udf_id].udf_num) {
        case 0:
#if defined(BCM_ENDURO_SUPPORT) || defined(BCM_KATANA_SUPPORT)
            if(SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit) || SOC_IS_KATANA(unit)) {
                if((udf_id == 3) && 
                  !SHR_BITGET(fg->qset.udf_map, 0) && 
                  !SHR_BITGET(fg->qset.udf_map, 2)) {
                    /* qid = UDF1_31_0 */
                    qid = _bcmFieldQualifyData2;
                } else if((udf_id == 1) && 
                  !SHR_BITGET(fg->qset.udf_map, 0) && 
                  !SHR_BITGET(fg->qset.udf_map, 2)) {
                    /* qid = UDF1_95_64 */
                    qid = _bcmFieldQualifyData3;
                } else {
                    /* qid = UDF1_127_0 */
                    qid = _bcmFieldQualifyData0;
                }
            } else
#endif /* BCM_ENDURO_SUPPORT */            
          {
            qid = _bcmFieldQualifyData0;
          }
          break;
      case 1:
          qid = _bcmFieldQualifyData1;
          break;
      default:
          FP_UNLOCK(fc);
          FP_ERR(("FP(unit %d) Error: Unknown UDF\n", unit));
          return (BCM_E_PARAM);
    }


    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, qid, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, qid, &q_offset);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    f2_idx = (stage_fc->data_ctrl->num_elems - 1) - fc->udf[udf_id].user_num;

    /*
     * The data/mask pair passed in here is assumed to
     * be pre-formatted by the user as 4-byte user fields.
     * The byte arrays are assumed to be in network byte order.
     */

    sal_memcpy(&q_offset_temp, q_offset, sizeof(_bcm_field_qual_offset_t));

    q_offset_temp.offset += f2_idx * stage_fc->data_ctrl->elem_size * 8;
    q_offset_temp.width = stage_fc->data_ctrl->elem_size * 8;

    /* Read qualifier match value and mask. */
    rv = _bcm_field_qual_value_get(unit, &q_offset_temp, f_ent, 
                                   &data_word, &mask_word);
    FP_UNLOCK(fc);
    BCM_IF_ERROR_RETURN(rv);

    for (idx = 0; idx < stage_fc->data_ctrl->elem_size; idx++) {
        data[idx] =
            (data_word >> ((stage_fc->data_ctrl->elem_size - 1 - idx) * 8)) &
            0xff;
        mask[idx] =
            (mask_word >> ((stage_fc->data_ctrl->elem_size - 1 - idx) * 8)) &
            0xff;
    }

    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_HiGig_get
 * Purpose:
 *      Qualify on HiGig packets.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_HiGig_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    _field_control_t *fc;     /* Field control structure. */
    _field_entry_t   *f_ent;  /* Field entry structure.   */
    int rv = BCM_E_UNAVAIL;   /* Operation return status. */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    if (SOC_IS_TRX(unit) || SOC_IS_EASYRIDER(unit)) {
        /* Read qualifier match value and mask. */
        return  _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                                     bcmFieldQualifyHiGig,
                                                     data, mask);
    } else if (SOC_IS_FBX(unit)) {
        BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
        FP_LOCK(fc);

        rv = _field_entry_get(unit, entry, _FP_ENTRY_PRIMARY, &f_ent);

        FP_UNLOCK(fc);
        BCM_IF_ERROR_RETURN(rv);

        /* Add data & mask to entry. */
        *data = f_ent->tcam.higig;
        *mask = f_ent->tcam.higig_mask;
    }
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InterfaceClassPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInterfaceClassPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InterfaceClassPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifyInterfaceClassPort,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InterfaceClassL2_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInterfaceClassL2
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InterfaceClassL2_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifyInterfaceClassL2,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InterfaceClassL3_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInterfaceClassL3
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InterfaceClassL3_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifyInterfaceClassL3,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcClassL2_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcClassL2
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcClassL2_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifySrcClassL2,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcClassL3_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcClassL3
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcClassL3_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifySrcClassL3,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcClassField_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcClassField
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcClassField_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifySrcClassField,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstClassL2_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstClassL2
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstClassL2_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifyDstClassL2,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstClassL3_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstClassL3
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstClassL3_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifyDstClassL3,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstClassField_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstClassField
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstClassField_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                             bcmFieldQualifyDstClassField,
                             data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3IntfGroup_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3IntfGroup
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3IntfGroup_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_if_group_t *data, 
    bcm_if_group_t *mask)
{
    return bcm_esw_field_qualify_InterfaceClassL3_get(unit, entry, 
                                                      (uint32 *)data, 
                                                      (uint32 *)mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpProtocolCommon_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpProtocolCommon
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      protocol - (OUT) Qualifier protocol encoding.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpProtocolCommon_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpProtocolCommon_t *protocol)
{
    return _field_qualify_IpProtocolCommon_get(unit, entry, 
                                    bcmFieldQualifyIpProtocolCommon,
                                    protocol);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIpProtocolCommon_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIpProtocolCommon
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      protocol - (OUT) Qualifier inner ip protocol encodnig.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIpProtocolCommon_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpProtocolCommon_t *protocol)
{
    return _field_qualify_IpProtocolCommon_get(unit, entry, 
                                    bcmFieldQualifyInnerIpProtocolCommon,
                                    protocol);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Snap_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySnap
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Snap_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_snap_header_t *data, 
    bcm_field_snap_header_t *mask)
{
    _bcm_field_qual_offset_t *q_offset;
    _field_entry_t           *f_ent;
    uint32                   ref_data[_FP_QUAL_DATA_WORDS]; 
    uint32                   ref_mask[_FP_QUAL_DATA_WORDS];
    int                      rv;

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    /* Initialization. */
    sal_memset(ref_data, 0, 2 * sizeof(uint32)); 
    sal_memset(ref_mask, 0, 2 * sizeof(uint32)); 

    /* Get field entry part that contains the qualifier. */
    rv = _bcm_field_entry_qual_get(unit, entry, 
                                   bcmFieldQualifySnap, &f_ent);
    BCM_IF_ERROR_RETURN(rv);

    /* Get qualifier offsets in the tcam. */
    rv = _field_qual_offset_get(unit, f_ent, 
                                bcmFieldQualifySnap, &q_offset);
    BCM_IF_ERROR_RETURN(rv);

    /* Read qualifier match value and mask. */
    rv = _bcm_field_qual_value_get(unit, q_offset, f_ent, 
                                   ref_data, ref_mask);
    BCM_IF_ERROR_RETURN(rv);

    data->org_code = (ref_data[1] << 16) | (ref_data[0] >> 16);
    data->type = ref_data[0] & 0xffff;

    mask->org_code = (ref_mask[1] << 16) | (ref_mask[0] >> 16);
    mask->type = ref_mask[0] & 0xffff;

    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Llc_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyLlc
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Llc_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_llc_header_t *data, 
    bcm_field_llc_header_t *mask)
{
    uint32    hw_data = 0;       /* HW buffer data.             */
    uint32    hw_mask = 0;       /* HW buffer mask.             */
    int       rv;                /* Operation return stauts.    */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                               bcmFieldQualifyLlc,
                                               &hw_data, &hw_mask);
    BCM_IF_ERROR_RETURN(rv);

    data->dsap    = (hw_data>> 16) & 0xff;
    data->ssap    = (hw_data >> 8)  & 0xff;
    data->control = hw_data & 0xff;

    mask->dsap    = (hw_mask >> 16) & 0xff;
    mask->ssap    = (hw_mask >> 8)  & 0xff;
    mask->control = hw_mask & 0xff;

    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerTpid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerTpid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      tpid - (OUT) Qualifier tpid.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerTpid_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *tpid)
{
    uint32    hw_data = 0;       /* HW buffer data.             */
    uint32    hw_mask = 0;       /* HW buffer mask.             */
    int       rv;                /* Operation return stauts.    */

    /* Input parameters check. */
    if (NULL == tpid) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                               bcmFieldQualifyInnerTpid,
                                               &hw_data, &hw_mask);
    BCM_IF_ERROR_RETURN(rv);

    rv = _field_tpid_hw_decode(unit, hw_data, tpid);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_OuterTpid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOuterTpid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      tpid - (OUT) Qualifier tpid.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterTpid_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *tpid)
{
    uint32    hw_data = 0;       /* HW buffer data.             */
    uint32    hw_mask = 0;       /* HW buffer mask.             */
    int       rv;                /* Operation return stauts.    */

    /* Input parameters check. */
    if (NULL == tpid) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                               bcmFieldQualifyOuterTpid,
                                               &hw_data, &hw_mask);
    BCM_IF_ERROR_RETURN(rv);

    rv = _field_tpid_hw_decode(unit, hw_data, tpid);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_PortClass_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyPortClass
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_PortClass_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return bcm_esw_field_qualify_InterfaceClassPort_get(unit, entry, 
                                                        data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3Routable_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3Routable
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3Routable_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                                bcmFieldQualifyL3Routable,
                                                data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpFrag_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpFrag
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      frag_info - (OUT) Qualifier ip framentation encoding.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpFrag_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpFrag_t *frag_info)
{
    int             rv = BCM_E_UNAVAIL;
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) \
    || defined(BCM_RAPTOR_SUPPORT)
    _field_control_t *fc;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    if (SOC_IS_FIREBOLT2(unit) || SOC_IS_TRX(unit) || 
        SOC_IS_RAVEN(unit) || SOC_IS_HAWKEYE(unit)) {
        rv = _field_qualify_IpFrag_get(unit, entry, 
                                       bcmFieldQualifyIpFrag, 
                                       frag_info);
    }
    FP_UNLOCK(fc);
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT || BCM_RAPTOR_SUPPORT */
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_LookupClass0_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyLookupClass0
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_LookupClass0_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return  bcm_esw_field_qualify_DstClassField_get(unit, entry, data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Vrf_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyVrf
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Vrf_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                                 bcmFieldQualifyVrf,
                                                 data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3Ingress_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3Ingress
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3Ingress_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                                 bcmFieldQualifyL3Ingress,
                                                 data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_ExtensionHeaderType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyExtensionHeaderType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ExtensionHeaderType_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyExtensionHeaderType,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_ExtensionHeaderSubCode_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyExtensionHeaderSubCode
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ExtensionHeaderSubCode_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyExtensionHeaderSubCode,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_ExtensionHeader2Type_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyExtensionHeader2Type
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ExtensionHeader2Type_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyExtensionHeader2Type,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L4Ports_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL4Ports
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L4Ports_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyL4Ports,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_MirrorCopy_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyMirrorCopy
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_MirrorCopy_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyMirrorCopy,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_TunnelTerminated_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTunnelTerminated
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TunnelTerminated_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyTunnelTerminated,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_MplsTerminated_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyMplsTerminated
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_MplsTerminated_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    _field_group_t *fg;         /* Field group structure        */
    int i = 0;                  /* Entry parts                  */
    int rv = BCM_E_INTERNAL;    /* Operation return stauts.     */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask))  {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint8_get(unit, entry,
                                    bcmFieldQualifyMplsTerminated,
                                    data, mask);
    BCM_IF_ERROR_RETURN(rv);
    if (SOC_IS_TRIUMPH2(unit)) {
        BCM_IF_ERROR_RETURN(_bcm_field_entry_group_find(unit, entry, &fg));
        for (i = 0; i < _FP_MAX_ENTRY_WIDTH; i++) {
            if ((int8) bcmFieldTunnelTypeMpls
                    == fg->sel_codes[i].loopback_type_sel) {
                if ((uint8) bcmFieldTunnelTypeMpls == (*data & *mask)) {
                    *data = 0x1;
                    *mask = 0x1;
                }
                break;
            }
        }
    }
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerSrcIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerSrcIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerSrcIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip_t *data, 
    bcm_ip_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                              bcmFieldQualifyInnerSrcIp,
                                              data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerDstIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDstIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerDstIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip_t *data, 
    bcm_ip_t *mask)
{
    /* Read qualifier match value and mask. */ 
    return  _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                                  bcmFieldQualifyInnerDstIp,
                                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerSrcIp6_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerSrcIp6
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerSrcIp6_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifyInnerSrcIp6,
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerDstIp6_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDstIp6
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerDstIp6_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifyInnerDstIp6, 
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerSrcIp6High_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerSrcIp6High
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerSrcIp6High_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifyInnerSrcIp6High,
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerDstIp6High_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDstIp6High
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerDstIp6High_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return _field_qualify_ip6_get(unit, entry,
                                  bcmFieldQualifyInnerDstIp6High,
                                  data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMultipath
 * Purpose:
 *     Add a multipath egress object field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field Entry id.
 *      mpintf - (IN) Multipath egress object id. 
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_esw_field_qualify_DstMultipath(int               unit, 
                                   bcm_field_entry_t entry, 
                                   bcm_if_t          mpintf
                                   )
{
    int rv = BCM_E_UNAVAIL;   /* Operation return status. */

#if defined(INCLUDE_L3)
    _field_control_t *fc;   /* Field control structure. */
    uint32 data;            /* HW data match criteria.  */
    uint32 mask;            /* HW data mask.            */
    uint32 flags;           /* L3 forwarding flags      */
    int nh_ecmp_id;         /* Next hop/Ecmp group id.  */

    /* Get next hop id. */
    rv = bcm_xgs3_l3_egress_id_parse(unit, mpintf, &flags, &nh_ecmp_id);
    BCM_IF_ERROR_RETURN(rv);

    if (!(flags & BCM_L3_MULTIPATH)) {
        return (BCM_E_UNAVAIL);
    }

    data = nh_ecmp_id;
    mask = (BCM_FIELD_EXACT_MATCH_MASK);

    BCM_IF_ERROR_RETURN(_field_dest_type_qualify(unit,
        entry, bcmFieldQualifyDstMultipath, &data, &mask, 0));

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify32(unit, entry, bcmFieldQualifyDstMultipath, 
                          data, mask);

    FP_UNLOCK(fc);
#endif /* INCLUDE_L3 */

    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMultipath_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstMultipath
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      mpintf - (OUT) Multipath egress object id. 
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMultipath_get(int               unit,
                                       bcm_field_entry_t entry, 
                                       bcm_if_t          *mpintf
                                       )
{
    int               rv = BCM_E_UNAVAIL;  /* Operation return status. */
#if defined(INCLUDE_L3)
    uint32            data; /* HW data match criteria.  */
    uint32            mask; /* HW data mask.            */

    /* Input parameters check. */
    if (NULL == mpintf) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifyDstMultipath,
                                           &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
        entry, bcmFieldQualifyDstMultipath, &data, &mask));

    *mpintf = data + BCM_XGS3_MPATH_EGRESS_IDX_MIN;
#endif /* INCLUDE_L3 */
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerTtl_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerTtl
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerTtl_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyInnerTtl,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerTos_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDSCP
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerTos_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyInnerTos,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerDSCP_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDSCP
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerDSCP_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyInnerDSCP,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIpProtocol_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIpProtocol
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIpProtocol_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyInnerIpProtocol,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIpFrag_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIpFrag
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      frag_info - (OUT) Inner ip header fragmentation info.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIpFrag_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpFrag_t *frag_info)
{
    int             rv = BCM_E_UNAVAIL;
#if  defined(BCM_TRX_SUPPORT) 
    _field_control_t *fc;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    if (SOC_IS_TRX(unit)) {
        rv = _field_qualify_IpFrag_get(unit, entry, 
                                       bcmFieldQualifyInnerIpFrag,
                                       frag_info);
    }
    FP_UNLOCK(fc);
#endif /* BCM_TRX_SUPPORT */
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DosAttack_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDosAttack
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DosAttack_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyDosAttack,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpmcStarGroupHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpmcStarGroupHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpmcStarGroupHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyIpmcStarGroupHit,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_MyStationHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyMyStationHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_MyStationHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyMyStationHit,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2PayloadFirstEightBytes_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2PayloadFirstEightBytes
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data1 - (OUT) Qualifier first four bytes of match data.
 *      data2 - (OUT) Qualifier last four bytes of match data.
 *      mask1 - (OUT) Qualifier first four bytes of match mask.
 *      mask2 - (OUT) Qualifier last four bytes of match mask.
 *
 * Note: Values returned in data1 and data2 are in actual packet data format
 *       order.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2PayloadFirstEightBytes_get(int unit, 
                                                   bcm_field_entry_t entry,
                                                   uint32 *data1, uint32 *data2,
                                                   uint32 *mask1, uint32 *mask2)
{
    int rv;

    /* Input parameters check. */
    if ((NULL == data1) || (NULL == data2) ||
        (NULL == mask1) || (NULL == mask2)) {
        return (BCM_E_PARAM);
    }

    rv = _field_qualify_L2PayloadFirstEightBytes_get(unit, entry, 
            bcmFieldQualifyL2PayloadFirstEightBytes, data1, data2, mask1, mask2);

    return rv;
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3DestRouteHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3DestRouteHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3DestRouteHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyL3DestRouteHit,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3DestHostHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3DestHostHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3DestHostHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyL3DestHostHit,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3SrcHostHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3SrcHostHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3SrcHostHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyL3SrcHostHit,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2CacheHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2CacheHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2CacheHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyL2CacheHit,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2StationMove_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2StationMove
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2StationMove_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyL2StationMove,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2DestHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2DestHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2DestHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyL2DestHit,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2SrcStatic_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2SrcStatic
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2SrcStatic_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyL2SrcStatic,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2SrcHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2SrcHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2SrcHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyL2SrcHit,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IngressStpState_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIngressStpState
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IngressStpState_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    uint32    hw_data = 0;       /* HW buffer data.             */
    uint32    hw_mask = 0;       /* HW buffer mask.             */
    int       rv;                /* Operation return stauts.    */

    /* Input parameters check. */
    if ((NULL == data) || (NULL == mask)) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                               bcmFieldQualifyIngressStpState,
                                               &hw_data, &hw_mask);
    BCM_IF_ERROR_RETURN(rv);

    switch (hw_data & hw_mask) {
      case 0: 
          *data = BCM_STG_STP_DISABLE;
          break;
      case 1: 
          *data = BCM_STG_STP_BLOCK;
          break;
      case 2: 
          *data = BCM_STG_STP_LEARN;
          break;
      case 3: 
          *data = BCM_STG_STP_FORWARD;
          break;
      default:
          return (BCM_E_INTERNAL);
    }
    *mask = (0 == hw_mask) ? 0 : 0xff;
    return (BCM_E_NONE);
}

/*
 * Function:
 *      bcm_esw_field_qualify_ForwardingVlanValid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyForwardingVlanValid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ForwardingVlanValid_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyForwardingVlanValid,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcVirtualPortValid_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifySrcVirtualPortValid
 *      qualifier from the field entry.
 * Parameters:
 *      unit    - (IN) Unit number.
 *      entry   - (IN) BCM field entry id.
 *      data    - (OUT) Qualifier match data.
 *      mask    - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcVirtualPortValid_get(
    int unit,
    bcm_field_entry_t entry,
    uint8 *data,
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry,
                                    bcmFieldQualifySrcVirtualPortValid,
                                    data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstL3EgressNextHops_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifyDstL3EgressNextHops
 *      qualifier from the field entry.
 * Parameters:
 *      unit    - (IN) Unit number.
 *      entry   - (IN) BCM field entry id.
 *      data    - (OUT) Qualifier match data.
 *      mask    - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstL3EgressNextHops_get(int unit,
    bcm_field_entry_t entry,
    uint32 *data,
    uint32 *mask)
{
    int rv = BCM_E_UNAVAIL;  /* Operation return status. */

#if defined(INCLUDE_L3)
    /* Check if L3 feature is supported on the device */
    if (!soc_feature(unit, soc_feature_l3)) {
        return (rv);
    }

    /*  Make sure module was initialized. */
    if (!BCM_XGS3_L3_INITIALIZED(unit)) {
        return (rv);
    }

    /* Read qualifier match value and mask. */ 
    rv =  _bcm_field_entry_qualifier_uint32_get(unit, entry,
                bcmFieldQualifyDstL3EgressNextHops,
                data, mask);
    BCM_IF_ERROR_RETURN(rv);
    
    *mask = *mask & (BCM_XGS3_L3_NH_TBL_SIZE(unit) - 1);

    /* Clear destination type in data and mask */
    BCM_IF_ERROR_RETURN(_field_dest_type_clear(unit,
        entry, bcmFieldQualifyDstL3EgressNextHops, data, mask));
#endif
    return (rv);

}

/*
 * Function:
 *      bcm_esw_field_qualify_VlanTranslationHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyVlanTranslationHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_VlanTranslationHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                   bcmFieldQualifyVlanTranslationHit,
                                   data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpAuth_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpAuth
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpAuth_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_BigIcmpCheck_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyBigIcmpCheck
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      flag - (OUT) Flag.
 *      size - (OUT) Size.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_BigIcmpCheck_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *flag, 
    uint32 *size)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IcmpTypeCode_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIcmpTypeCode
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IcmpTypeCode_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *data, 
    uint16 *mask)
{
    int rv = BCM_E_INTERNAL;
    uint32 data_hw = 0, mask_hw = 0;

    /* Read qualifier match value and mask. */
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry,
                                             bcmFieldQualifyIcmpTypeCode,
                                             &data_hw, &mask_hw);
    *data = (uint16) data_hw;
    *mask = (uint16) mask_hw;
    return rv;
}

/*
 * Function:
 *      bcm_esw_field_qualify_IgmpTypeMaxRespTime_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIgmpTypeMaxRespTime
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IgmpTypeMaxRespTime_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *data, 
    uint16 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_TranslatedVlanFormat_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTranslatedVlanFormat
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TranslatedVlanFormat_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    _field_control_t *fc;       /* Field control structure. */
    int              rv;        /* Operation return status. */


    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_qualify_VlanFormat_get(unit, entry, 
                                          bcmFieldQualifyTranslatedVlanFormat,
                                          data, mask);
    FP_UNLOCK(fc);
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_IntPriority_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIntPriority
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IntPriority_get(int unit, bcm_field_entry_t entry,
                                      uint8 *data, uint8 *mask)
{
    /* Read qualifier match value and mask. */
    return _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                            bcmFieldQualifyIntPriority,
                                            data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_Color_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyColor
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      color - (OUT) Qualifier match color.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Color_get(int unit, bcm_field_entry_t entry, 
                                uint8 *color)
{
    int rv;          /* Operation return status. */
    uint8 data;      /* Qualifier data.          */
    uint8 mask;      /* Qualifier mask.          */

    /* Read qualifier match value and mask. */
    rv = _bcm_field_entry_qualifier_uint8_get(unit, entry, bcmFieldQualifyColor,
                                          &data, &mask);
    BCM_IF_ERROR_RETURN(rv);
    switch (data) {
      case 0:
          *color = BCM_FIELD_COLOR_GREEN;
          break;
      case 1:
          *color = BCM_FIELD_COLOR_RED;
          break;
      case 3:
          *color = BCM_FIELD_COLOR_YELLOW;
          break;
      default:
          rv = BCM_E_INTERNAL;
    }
    return (rv);
}

/*
 * Function:
 *      bcm_esw_field_qualify_FibreChannOuter_get
 * Purpose:
 *      Get Fibre Channel outer header type field qualification from a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      fibre_chan_type - (OUT) Fibre Channel header type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FibreChanOuter_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_FibreChan_t *fibre_chan_type)
{
    uint8            data; /* HW data match criteria.  */
    uint8            mask; /* HW data mask.            */
    int              rv;   /* Operation return status. */

    /* Input parameters check. */
    if (NULL == fibre_chan_type) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */
    rv = _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                          bcmFieldQualifyFibreChanOuter,
                                          &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    switch (data) {
      case 0x1:
          *fibre_chan_type = bcmFieldFibreChan;
          break;
      case 0x2:
          *fibre_chan_type = bcmFieldFibreChanVirtual;
          break;
      case 0x3:
          *fibre_chan_type = bcmFieldFibreChanEncap;
          break;
      case 0x4:
          *fibre_chan_type = bcmFieldFibreChanRouted;
          break;
      default:
          return (BCM_E_INTERNAL);
    }
    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_FibreChannInner_get
 * Purpose:
 *      Get Fibre Channel inner header type field qualification from a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      fibre_chan_type - (OUT) Fibre Channel header type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FibreChanInner_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_FibreChan_t *fibre_chan_type)
{
    uint8            data; /* HW data match criteria.  */
    uint8            mask; /* HW data mask.            */
    int              rv;   /* Operation return status. */

    /* Input parameters check. */
    if (NULL == fibre_chan_type) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */
    rv = _bcm_field_entry_qualifier_uint8_get(unit, entry, 
                                          bcmFieldQualifyFibreChanInner,
                                          &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    switch (data) {
      case 0x1:
          *fibre_chan_type = bcmFieldFibreChan;
          break;
      case 0x2:
          *fibre_chan_type = bcmFieldFibreChanVirtual;
          break;
      case 0x3:
          *fibre_chan_type = bcmFieldFibreChanEncap;
          break;
      case 0x4:
          *fibre_chan_type = bcmFieldFibreChanRouted;
          break;
      default:
          return (BCM_E_INTERNAL);
    }
    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_VnTag_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifyVnTag
 *      qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_VnTag_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                                 bcmFieldQualifyVnTag,
                                                 data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_CnTag_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifyCnTag
 *      qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_CnTag_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                                 bcmFieldQualifyCnTag,
                                                 data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_FabricQueueTag_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifyFabricQueueTag
 *      qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FabricQueueTag_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    /* Read qualifier match value and mask. */ 
    return _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                                 bcmFieldQualifyFabricQueueTag,
                                                 data, mask);
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModPortGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcModPortGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit  - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      port  - (OUT) Qualifier match gport.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModPortGport_get(int unit, 
                                          bcm_field_entry_t entry, 
                                          bcm_gport_t *port)
{
    uint32 data;   /* HW encoded qualifier data.  */
    uint32 mask;   /* HW encoding qualifier mask. */
    int rv;        /* Operation return status.    */

    /* Input parameters check. */
    if (NULL == port) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifySrcModPortGport,
                                           &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    BCM_GPORT_MODPORT_SET(*port, ((data >> _FP_PORT_BITWIDTH(unit)) & 0xff), 
                          (data & 0x3f));

    return BCM_E_NONE; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModuleGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcModuleGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit  - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      port  - (OUT) Qualifier match gport.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModuleGport_get(int unit, 
                                          bcm_field_entry_t entry,
                                          bcm_gport_t *port)
{
    uint32 data;   /* HW encoded qualifier data.  */
    uint32 mask;   /* HW encoding qualifier mask. */
    int rv;        /* Operation return status.    */

    /* Input parameters check. */
    if (NULL == port) {
        return (BCM_E_PARAM);
    }

    /* Read qualifier match value and mask. */ 
    rv = _bcm_field_entry_qualifier_uint32_get(unit, entry, 
                                           bcmFieldQualifySrcModuleGport,
                                           &data, &mask);
    BCM_IF_ERROR_RETURN(rv);

    BCM_GPORT_MODPORT_SET(*port, (data & 0xff), 0);

    return BCM_E_NONE; 
}


#ifdef BROADCOM_DEBUG

/* Section: Field Debug */


/*
 * Function: bcm_field_show
 *
 * Purpose:
 *     Show current S/W state if compiled in debug mode.
 *
 * Parameters:
 *     unit - BCM device number
 *     pfx - Character string to prefix output lines
 *
 * Returns:
 *     Nothing.
 */

int
bcm_esw_field_show(int unit, const char *pfx)
{
    int                 idx;
    _field_group_t      *fg;
    _field_range_t      *fr;
    _field_stage_t      *stage_fc;
    _field_control_t    *fc;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    stage_fc = fc->stages;

    FP_SHOW(("%s:\tunit %d:", pfx, unit));

    while(stage_fc) {
        switch (stage_fc->stage_id) {
          case _BCM_FIELD_STAGE_INGRESS: 
              FP_SHOW(("PIPELINE STAGE INGRESS\n"));
              break;
#if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
          case _BCM_FIELD_STAGE_LOOKUP: 
              FP_SHOW(("PIPELINE STAGE LOOKUP\n"));
              break;
          case _BCM_FIELD_STAGE_EGRESS: 
              FP_SHOW(("PIPELINE STAGE EGRESS\n"));
              break; 
#endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
          case _BCM_FIELD_STAGE_EXTERNAL:
              FP_SHOW(("PIPELINE STAGE EXTERNAL\n"));
              break; 
          default: 
              break;
        }

        FP_SHOW(("%s:\t      :tcam_sz=%d(%#x),", pfx, stage_fc->tcam_sz, stage_fc->tcam_sz));
        FP_SHOW((" tcam_slices=%d,", stage_fc->tcam_slices));
        FP_SHOW((" tcam_ext_numb=%d,", fc->tcam_ext_numb));
        FP_SHOW(("\n"));

        /* Display any range checkers defined. */
        if ((_BCM_FIELD_STAGE_INGRESS  == stage_fc->stage_id) ||
            (_BCM_FIELD_STAGE_EXTERNAL == stage_fc->stage_id)) {
            for (fr = stage_fc->ranges; fr != NULL; fr = fr->next) {
                _field_range_dump(pfx, fr);
            }
        }
        stage_fc = stage_fc->next;
    }
    /* Print the any defined UDFs. */
    for (idx = 0; idx < BCM_FIELD_USER_NUM_UDFS; idx++) {
        if (fc->udf[idx].valid) {
        FP_SHOW(("%s:\tudf %d: use_count=%d, udf_num=%s, user_num=%d\n",
                     pfx, idx, fc->udf[idx].use_count,
              _field_qual_name(fc->udf[idx].udf_num + _bcmFieldQualifyData0),
                     fc->udf[idx].user_num));
        }
    }

    /* Print the groups, along with their entries. */
    for (fg = fc->groups; fg != NULL ; fg = fg->next) {
        bcm_esw_field_group_dump(unit, fg->gid);
    }

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: bcm_field_entry_dump
 *
 * Purpose:
 *     Show contents of a field entry.
 *
 * Parameters:
 *     unit  - BCM device number
 *     entry - Field entry to dump
 *
 * Returns:
 *     Nothing.
 */
int
bcm_esw_field_entry_dump(int unit, bcm_field_entry_t entry)
{
    int                 parts_count;
    _field_group_t      *fg;
    _field_action_t     *fa;
    _field_control_t    *fc;
    _field_entry_t      *f_ent;
    uint8               idx;
    int                 rv;
#if defined(BCM_KATANA_SUPPORT)
    bcm_policer_t    policer_id = 0;
#endif

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _bcm_field_entry_get_by_id(unit, entry, &f_ent);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    fg = f_ent->group;
    FP_SHOW(("EID %3d: gid=%d,\n", f_ent->eid, fg->gid));

    /* Get number of entry parts. */
    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags,
                                            &parts_count);
    BCM_IF_ERROR_RETURN(rv);

    /* Dump the primary entry. */
    for(idx = 0; idx < parts_count; idx++) { 
        _field_entry_phys_dump(unit, f_ent + idx, idx);
    }

    /* Display action data */
    for(idx = 0; idx < parts_count; idx++) {
        fa = f_ent[idx].actions;
        while (fa != NULL) {
            FP_SHOW(("         action="));
            _field_action_dump(fa);
            FP_SHOW(("\n"));
            fa = fa->next;
        }
    }
#if defined(BCM_KATANA_SUPPORT)
    if (SOC_IS_KATANA(unit)) {
        if (_BCM_FIELD_STAGE_LOOKUP == f_ent->group->stage_id) {
            if (f_ent->global_meter_policer.pid) {
                policer_id = f_ent->global_meter_policer.pid;
            } 
        }
        FP_SHOW((" Global Meter policer=%x", policer_id));
    }
#endif

    /* Display entry's meter. */
    FP_SHOW(("         policer="));
    _field_policers_dump(unit, f_ent);

    /* Display entry's counter. */
    FP_SHOW(("         statistics="));
    BCM_IF_ERROR_RETURN(_field_stat_dump(unit, f_ent));
    FP_SHOW(("\n"));

    FP_UNLOCK(fc);
    return (BCM_E_NONE);
}

/*
 * Function: bcm_field_group_dump
 *
 * Purpose:
 *     Show contents of a field group.
 *
 * Parameters:
 *     unit  - BCM device number
 *     group - Field group to dump
 *
 * Returns:
 *     Nothing.
 */
int
bcm_esw_field_group_dump(int unit, bcm_field_group_t group)
{
    _field_stage_t      *stage_fc;
    _field_group_t      *fg;
    _field_control_t    *fc;
    int                 enable;
    int                 parts_count;
    int                 idx;
    char                buf[100];
    int                 rv;
    int entry_count;
    int entry_index;
    bcm_field_entry_t *entry_ids;

    BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    FP_LOCK(fc);

    rv = _field_group_get(unit, group, &fg);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    rv = _bcm_field_entry_tcam_parts_count (unit, fg->flags, &parts_count);
    if (BCM_FAILURE(rv)) {
        FP_UNLOCK(fc);
        return (rv);
    }

    if ((fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) && 
        (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE)) {
        FP_SHOW(("Quad wide intra-slice group, "));
    } else if ((fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) && 
               (fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE)) {
        FP_SHOW(("Intra-slice double wide group, "));
    } 
    FP_SHOW(("GID %10d: gid=%d, mode=%s, stage=%s ", group,
             fg->gid, _field_group_mode_name(fg->flags), 
             SOC_IS_EASYRIDER(unit) ? \
             _field_qual_stage_name(fg->stage_id) : \
             _field_stage_name(stage_fc)));
    bcm_esw_field_group_enable_get(unit, group, &enable);
    if (enable) {
        FP_SHOW(("lookup=Enabled, "));
    } else {
        FP_SHOW(("lookup=Disabled, "));
    }

    FP_SHOW(("pbmp={%s}\n", SOC_PBMP_FMT(fg->pbmp, buf)));

    _field_qset_dump("         qset=", fg->qset, ",\n");


    for (idx = 0; idx < parts_count; idx++) {
        sal_sprintf(buf, "         selcodes[%d]=\n", idx);
        _field_selcode_dump(unit, buf, fg->sel_codes + idx,  ", ");
        _field_qual_list_dump(" ",fg, idx,",\n");

    }

    FP_SHOW(("\n"));

    /* Print the primary slice data. */
    FP_SHOW(("         slice_pri="));
    _field_slice_dump(unit, "                    ", &fg->slices[0], "\n");

    /* Print the secondary slice data. */
    if ((fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) ||
        (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE)) {
        FP_SHOW(("         slice_sec="));
        _field_slice_dump(unit, "                    ", &fg->slices[1], "\n");
    }

    /* Print the tertiary slice data. */
    if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
        FP_SHOW(("         slice_ter="));
        _field_slice_dump(unit, "                    ", &fg->slices[2], "\n");
                                
    }

    /* Print group used resources status */
    if (BCM_SUCCESS(_field_group_status_calc(unit, fg))) {
        FP_SHOW(("         group_status="));
        _field_group_status_dump(&fg->group_status);
        FP_SHOW(("\n"));
    }

    /* Print group's entries */

    rv = bcm_esw_field_entry_multi_get(unit, group, 0, NULL, &entry_count);

    if (BCM_SUCCESS(rv))
    {
        entry_ids = sal_alloc(entry_count * sizeof (bcm_field_entry_t),
            "Entry ID array");

        if (entry_ids == NULL)
        {
            rv = BCM_E_MEMORY;
        }
        else
        {
            rv = bcm_esw_field_entry_multi_get(unit, group, entry_count,
                entry_ids, &entry_count);

            if (BCM_SUCCESS(rv))
            {
                for (entry_index = 0; entry_index < entry_count;
                    ++entry_index)
                {
                    bcm_esw_field_entry_dump(unit, entry_ids[entry_index]);
                }
            }

            sal_free(entry_ids);
        }
    }

    FP_UNLOCK(fc);
    return (BCM_E_NONE); 
}
#endif /* BROADCOM_DEBUG */
#else  /* !BCM_FIELD_SUPPORT */



int
bcm_esw_field_init(int unit)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_detach(int unit)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_flush(int unit, bcm_field_group_t group)
{
    return BCM_E_UNAVAIL;
}


int
bcm_esw_field_status_get(int unit, bcm_field_status_t *status)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_control_get(int unit, bcm_field_control_t control, uint32 *state)
{
    return (BCM_E_UNAVAIL);
}


int
bcm_esw_field_control_set(int unit, bcm_field_control_t control, uint32 state)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_create(int unit,
                           bcm_field_qset_t qset,
                           int pri,
                           bcm_field_group_t *group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_create_id(int unit,
                              bcm_field_qset_t qset,
                              int pri,
                              bcm_field_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_create_mode(int unit,
                                   bcm_field_qset_t qset,
                                   int pri,
                                   bcm_field_group_mode_t mode,
                                   bcm_field_group_t *group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_create_mode_id(int unit,
                                   bcm_field_qset_t qset,
                                   int pri,
                                   bcm_field_group_mode_t mode,
                                   bcm_field_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_port_create_mode(int unit, bcm_port_t port,
                                         bcm_field_qset_t qset, int pri,
                                     bcm_field_group_mode_t mode,
                                     bcm_field_group_t *group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_port_create_mode_id(int unit, bcm_port_t port,
                                        bcm_field_qset_t qset, int pri,
                                        bcm_field_group_mode_t mode,
                                        bcm_field_group_t group)
{
    return (BCM_E_UNAVAIL);
}


int
bcm_esw_field_group_ports_create_mode(int unit, bcm_pbmp_t pbmp,
                                      bcm_field_qset_t qset, int pri,
                                      bcm_field_group_mode_t mode,
                                      bcm_field_group_t *group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_ports_create_mode_id(int unit, bcm_pbmp_t pbmp,
                                         bcm_field_qset_t qset, int pri,
                                         bcm_field_group_mode_t mode,
                                         bcm_field_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_mode_get(int unit,
                             bcm_field_group_t group,
                             bcm_field_group_mode_t *mode)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_set(int unit,
                        bcm_field_group_t group,
                        bcm_field_qset_t qset)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_get(int unit,
                        bcm_field_group_t group,
                        bcm_field_qset_t *qset)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_destroy(int unit,
                            bcm_field_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_status_get(int unit,
                               bcm_field_group_t group,
                               bcm_field_group_status_t *status)
{
    return (BCM_E_UNAVAIL);
}

    int
bcm_esw_field_group_enable_set(int unit, bcm_field_group_t group, int enable)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_enable_get(int unit, bcm_field_group_t group, int *enable)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_range_create_id(int unit,
                              bcm_field_range_t range,
                              uint32 flags,
                              bcm_l4_port_t min,
                              bcm_l4_port_t max)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_range_create(int unit,
                           bcm_field_range_t *range,
                           uint32 flags,
                           bcm_l4_port_t min,
                           bcm_l4_port_t max)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_range_group_create_id(int unit,
                                    bcm_field_range_t range,
                                    uint32 flags,
                                    bcm_l4_port_t min,
                                    bcm_l4_port_t max,
                                    bcm_if_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_range_group_create(int unit,
                                 bcm_field_range_t *range,
                                 uint32 flags,
                                 bcm_l4_port_t min,
                                 bcm_l4_port_t max,
                                 bcm_if_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_range_get(int unit,
                        bcm_field_range_t range,
                        uint32 *flags,
                        bcm_l4_port_t *min,
                        bcm_l4_port_t *max)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_range_destroy(int unit,
                            bcm_field_range_t range)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_range_set(int unit,
                              bcm_field_group_t group,
                              uint32 flags,
                              bcm_l4_port_t min,
                              bcm_l4_port_t max)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_range_get(int unit,
                              bcm_field_group_t group,
                              uint32 *flags,
                              bcm_l4_port_t *min,
                              bcm_l4_port_t *max)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_udf_spec_set(int unit,
                           bcm_field_udf_spec_t *udf_spec,
                           uint32 flags,
                           uint32 offset)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_udf_spec_get(int unit,
                           bcm_field_udf_spec_t *udf_spec,
                           uint32 *flags,
                           uint32 *offset)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_udf_create(int unit,
                         bcm_field_udf_spec_t *udf_spec,
                         bcm_field_udf_t *udf_id)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_udf_create_id(int unit,
                            bcm_field_udf_spec_t *udf_spec,
                            bcm_field_udf_t udf_id)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_udf_ethertype_set(int unit, int index, 
                                bcm_port_frametype_t frametype,
                                bcm_port_ethertype_t ethertype) 
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_udf_ethertype_get(int unit, int index,
                                bcm_port_frametype_t *frametype,
                                bcm_port_ethertype_t *ethertype) 
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_udf_ipprotocol_set(int unit, int index, uint32 flags, uint8 proto)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_udf_ipprotocol_get(int unit, int index, uint32 *flags,
                                 uint8 *proto)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_udf_get(int unit,
                      bcm_field_udf_spec_t *udf_spec,
                      bcm_field_udf_t udf_id)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_udf_destroy(int unit,
                          bcm_field_udf_t udf_id)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qset_add_udf(int unit,
                           bcm_field_qset_t *qset,
                           bcm_field_udf_t udf_id)

{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qset_udf_get(int unit, bcm_field_qset_t *qset, int udf_max,
                       int *udf_arr, int *udf_count) 
{
    return (BCM_E_UNAVAIL);
}



int
bcm_esw_field_entry_create(int unit,
                           bcm_field_group_t group,
                           bcm_field_entry_t *entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_entry_create_id(int unit,
                              bcm_field_group_t group,
                              bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_entry_multi_get(int unit, bcm_field_group_t group,
    int entry_size, bcm_field_entry_t *entry_array, int *entry_count)
{
    return BCM_E_UNAVAIL;
}

int
bcm_esw_field_entry_destroy(int unit,
                            bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_entry_destroy_all(int unit)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_entry_copy(int unit,
                         bcm_field_entry_t src_entry,
                         bcm_field_entry_t *dst_entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_entry_copy_id(int unit,
                            bcm_field_entry_t src_entry,
                            bcm_field_entry_t dst_entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_entry_install(int unit,
                            bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_entry_reinstall(int unit,
                              bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_entry_remove(int unit,
                           bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_install(int unit,
                           bcm_field_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_remove(int unit,
                           bcm_field_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_entry_prio_get(int unit, bcm_field_entry_t entry, int *prio)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_entry_prio_set(int unit, bcm_field_entry_t entry, int prio)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_resync(int unit)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_clear(int unit, bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InPort(int unit, bcm_field_entry_t entry,
                             bcm_port_t data, bcm_port_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_OutPort(int unit, bcm_field_entry_t entry,
                             bcm_port_t data, bcm_port_t mask)
{
    return (BCM_E_UNAVAIL);
}



int
bcm_esw_field_qualify_InPorts(int unit, bcm_field_entry_t entry,
                              bcm_pbmp_t data, bcm_pbmp_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_OutPorts(int unit, bcm_field_entry_t entry,
                               bcm_pbmp_t data, bcm_pbmp_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Drop(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcModid(int unit, bcm_field_entry_t entry,
                               bcm_module_t data, bcm_module_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcPortTgid(int unit, bcm_field_entry_t entry,
                                  bcm_port_t data, bcm_port_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcPort(int unit, bcm_field_entry_t entry,
                              bcm_module_t data_modid,
                              bcm_module_t mask_modid,
                              bcm_port_t   data_port,
                              bcm_port_t   mask_port)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcTrunk(int unit, bcm_field_entry_t entry,
                               bcm_trunk_t data, bcm_trunk_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstModid(int unit, bcm_field_entry_t entry,
                               bcm_module_t data, bcm_module_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstPortTgid(int unit, bcm_field_entry_t entry,
                                  bcm_port_t data, bcm_port_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstPort(int unit, bcm_field_entry_t entry,
                              bcm_module_t data_modid,
                              bcm_module_t mask_modid,
                              bcm_port_t   data_port,
                              bcm_port_t   mask_port)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstTrunk(int unit, bcm_field_entry_t entry,
                               bcm_trunk_t data, bcm_trunk_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_L4SrcPort(int unit, bcm_field_entry_t entry,
                                bcm_l4_port_t data, bcm_l4_port_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_L4DstPort(int unit, bcm_field_entry_t entry,
                                bcm_l4_port_t data, bcm_l4_port_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerL4SrcPort(int unit, bcm_field_entry_t entry,
                                bcm_l4_port_t data, bcm_l4_port_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerL4DstPort(int unit, bcm_field_entry_t entry,
                                bcm_l4_port_t data, bcm_l4_port_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_OuterVlan(int unit, bcm_field_entry_t entry,
                                bcm_vlan_t data, bcm_vlan_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerVlan(int unit, bcm_field_entry_t entry,
                                bcm_vlan_t data, bcm_vlan_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_EtherType(int unit, bcm_field_entry_t entry,
                                uint16 data, uint16 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_IpProtocol(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_LookupStatus(int unit, bcm_field_entry_t entry,
                                   uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}


int 
bcm_esw_field_qualify_DosAttack(int unit, bcm_field_entry_t entry, 
                                uint8 data, uint8 mask) 
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_IpmcStarGroupHit(int unit, bcm_field_entry_t entry, 
                                       uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_MyStationHit(int unit, bcm_field_entry_t entry, 
                                       uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_L2PayloadFirstEightBytes(int unit, bcm_field_entry_t entry,
                                            uint32 data1, uint32 data2,
                                            uint32 mask1, uint32 mask2)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_L3DestRouteHit(int unit, bcm_field_entry_t entry, 
                                uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_L3DestHostHit(int unit, bcm_field_entry_t entry, 
                                uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_L3SrcHostHit(int unit, bcm_field_entry_t entry, 
                               uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_L2CacheHit(int unit, bcm_field_entry_t entry, 
                                  uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_L2StationMove(int unit, bcm_field_entry_t entry, 
                                    uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_L2DestHit(int unit, bcm_field_entry_t entry, 
                                uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_L2SrcStatic(int unit, bcm_field_entry_t entry, 
                                  uint8 data, uint8 mask) 
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_L2SrcHit(int unit, bcm_field_entry_t entry, 
                               uint8 data, uint8 mask) 
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_IngressStpState(int unit,bcm_field_entry_t entry, 
                                      uint8 data, uint8 mask) 
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_ForwardingVlanValid(int unit, bcm_field_entry_t entry, 
                                          uint8 data, uint8 mask) 
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_SrcVirtualPortValid(int unit,
                                          bcm_field_entry_t entry,
                                          uint8 data,
                                          uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstL3EgressNextHops(int unit,
    bcm_field_entry_t entry,
    uint32 data,
    uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_VlanTranslationHit(int unit, bcm_field_entry_t entry, 
                                         uint8 data, uint8 mask) 
{
    return (BCM_E_UNAVAIL);
}


int
bcm_esw_field_qualify_IpInfo(int unit, bcm_field_entry_t entry,
                             uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_PacketRes(int unit, bcm_field_entry_t entry,
                                uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcIp(int unit, bcm_field_entry_t entry,
                            bcm_ip_t data, bcm_ip_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstIp(int unit, bcm_field_entry_t entry,
                            bcm_ip_t data, bcm_ip_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DSCP(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Tos(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_IpFlags(int unit, bcm_field_entry_t entry,
                              uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_TcpControl(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Ttl(int unit, bcm_field_entry_t entry,
                          uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_RangeCheck(int unit, bcm_field_entry_t entry,
                                 bcm_field_range_t range, int invert)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcIp6(int unit, bcm_field_entry_t entry,
                             bcm_ip6_t data, bcm_ip6_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstIp6(int unit, bcm_field_entry_t entry,
                             bcm_ip6_t data, bcm_ip6_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcIp6High(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstIp6High(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcIp6Low(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstIp6Low(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Ip6NextHeader(int unit, bcm_field_entry_t entry,
                                    uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerIp6NextHeader(int unit, bcm_field_entry_t entry,
                                    uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}
int
bcm_esw_field_qualify_InnerIp6TrafficClass(int unit, bcm_field_entry_t entry,
                                      uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerIp6FlowLabel(int unit, bcm_field_entry_t entry,
                                   uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Ip6TrafficClass(int unit, bcm_field_entry_t entry,
                                      uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Ip6FlowLabel(int unit, bcm_field_entry_t entry,
                                   uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Ip6HopLimit(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerIp6HopLimit(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcMac(int unit, bcm_field_entry_t entry,
                             bcm_mac_t data, bcm_mac_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstMac(int unit, bcm_field_entry_t entry,
                             bcm_mac_t data, bcm_mac_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_PacketFormat(int unit, bcm_field_entry_t entry,
                                   uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcMacGroup(int unit, bcm_field_entry_t entry,
                                  uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_IpType(int unit, bcm_field_entry_t entry,
                             bcm_field_IpType_t data)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_ForwardingType(int unit, bcm_field_entry_t entry,
                             bcm_field_ForwardingType_t data)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_L2Format(int unit, bcm_field_entry_t entry,
                               bcm_field_L2Format_t type)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_VlanFormat(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_MHOpcode(int unit, bcm_field_entry_t entry,
                               uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_UserDefined(int unit, bcm_field_entry_t entry,
                                  bcm_field_udf_t udf_id,
                                  uint8 data[BCM_FIELD_USER_FIELD_SIZE],
                                  uint8 mask[BCM_FIELD_USER_FIELD_SIZE])
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Decap(int unit, bcm_field_entry_t entry,
                            bcm_field_decap_t decap)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_HiGig(int unit, bcm_field_entry_t entry,
                            uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_L3IntfGroup(int unit, bcm_field_entry_t entry,
                                  bcm_if_group_t data, bcm_if_group_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InterfaceClassL2(int unit, bcm_field_entry_t entry,
                                       uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InterfaceClassL3(int unit, bcm_field_entry_t entry,
                                       uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InterfaceClassPort(int unit, bcm_field_entry_t entry,
                                       uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcClassL2(int unit, bcm_field_entry_t entry,
                                 uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcClassL3(int unit, bcm_field_entry_t entry,
                                 uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_SrcClassField(int unit, bcm_field_entry_t entry,
                                     uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstClassL2(int unit, bcm_field_entry_t entry,
                                 uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstClassL3(int unit, bcm_field_entry_t entry,
                                 uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_DstClassField(int unit, bcm_field_entry_t entry,
                                     uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Stage(int unit, bcm_field_entry_t entry,
                            bcm_field_stage_t stage)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_SrcIpEqualDstIp(int unit, bcm_field_entry_t entry,
                            uint32 flag)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_EqualL4Port(int unit, bcm_field_entry_t entry,
                            uint32 flag)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_TcpSequenceZero(int unit, bcm_field_entry_t entry,
                            uint32 flag)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_TcpHeaderSize(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_IpProtocolCommon(int unit, bcm_field_entry_t entry,
                                       bcm_field_IpProtocolCommon_t protocol)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerIpProtocolCommon(int unit, bcm_field_entry_t entry,
                                       bcm_field_IpProtocolCommon_t protocol)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Snap(int unit, bcm_field_entry_t entry,
                           bcm_field_snap_header_t data, 
                           bcm_field_snap_header_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_Llc(int unit, bcm_field_entry_t entry,
                          bcm_field_llc_header_t data, 
                          bcm_field_llc_header_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerTpid(int unit, bcm_field_entry_t entry,
                                uint16 tpid)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_OuterTpid(int unit, bcm_field_entry_t entry,
                                uint16 tpid)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_PortClass(int unit, bcm_field_entry_t entry,
                                uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_L3Routable(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_IpFrag(int unit, bcm_field_entry_t entry,
                                  bcm_field_IpFrag_t frag_info)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_LookupClass0(int unit, bcm_field_entry_t entry,
                                       uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_Vrf(int unit, bcm_field_entry_t entry,
                              uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_L3Ingress(int unit, bcm_field_entry_t entry,
                              uint32 data, uint32 mask)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_L4Ports(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_MirrorCopy(int unit, bcm_field_entry_t entry,
                                  uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}


int bcm_esw_field_qualify_TunnelTerminated(int unit, bcm_field_entry_t entry,
                                           uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_MplsTerminated(int unit, bcm_field_entry_t entry,
                                           uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}


int bcm_esw_field_qualify_ExtensionHeaderType(int unit, 
                                              bcm_field_entry_t entry,
                                              uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_ExtensionHeaderSubCode(int unit, 
                                                 bcm_field_entry_t entry,
                                                 uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_qualify_ExtensionHeader2Type(int unit, 
                                              bcm_field_entry_t entry,
                                              uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_action_add(int unit,
                         bcm_field_entry_t entry,
                         bcm_field_action_t action,
                         uint32 param0,
                         uint32 param1)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_action_ports_add(int unit,
                               bcm_field_entry_t entry,
                               bcm_field_action_t action,
                               bcm_pbmp_t pbmp)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_action_get(int unit,
                         bcm_field_entry_t entry,
                         bcm_field_action_t action,
                         uint32 *param0,
                         uint32 *param1)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_action_ports_get(int unit,
                               bcm_field_entry_t entry,
                               bcm_field_action_t action,
                               bcm_pbmp_t *pbmp)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_action_delete(int unit, bcm_field_entry_t entry, 
                        bcm_field_action_t action, 
                        uint32 param0, uint32 param1)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_action_remove(int unit,
                            bcm_field_entry_t entry,
                            bcm_field_action_t action)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_action_remove_all(int unit,
                                bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_counter_create(int unit,
                             bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_counter_share(int unit,
                            bcm_field_entry_t src_entry,
                            bcm_field_entry_t dst_entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_counter_destroy(int unit,
                              bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_counter_set(int unit,
                          bcm_field_entry_t entry,
                          int counter_num,
                          uint64 val)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_counter_set32(int unit, bcm_field_entry_t entry, int counter_num,
                            uint32 val)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_counter_get(int unit,
                          bcm_field_entry_t entry,
                          int counter_num,
                          uint64 *valp)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_counter_get32(int unit,
                            bcm_field_entry_t entry,
                            int counter_num,
                            uint32 *valp)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_meter_create(int unit,
                           bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_meter_share(int unit,
                          bcm_field_entry_t src_entry,
                          bcm_field_entry_t dst_entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_meter_destroy(int unit,
                            bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_meter_set(int unit,
                        bcm_field_entry_t entry,
                        int meter_num,
                        uint32 kbits_sec,
                        uint32 kbits_burst)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_meter_get(int unit,
                        bcm_field_entry_t entry,
                        int meter_num,
                        uint32 *kbits_sec,
                        uint32 *kbits_burst)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_entry_dump(int unit, 
                         bcm_field_entry_t entry)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_dump(int unit,
                         bcm_field_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_show(int unit,
                   const char *pfx)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerSrcIp(int unit, bcm_field_entry_t entry,
                            bcm_ip_t data, bcm_ip_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerDstIp(int unit, bcm_field_entry_t entry,
                            bcm_ip_t data, bcm_ip_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerSrcIp6(int unit, bcm_field_entry_t entry,
                             bcm_ip6_t data, bcm_ip6_t mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerDstIp6(int unit, bcm_field_entry_t entry,
                             bcm_ip6_t data, bcm_ip6_t mask)
{
     return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerSrcIp6High(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
     return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerDstIp6High(int unit, bcm_field_entry_t entry,
                                 bcm_ip6_t data, bcm_ip6_t mask)
{
     return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerTos(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
     return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerDSCP(int unit, bcm_field_entry_t entry,
                           uint8 data, uint8 mask)
{
     return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerIpProtocol(int unit, bcm_field_entry_t entry,
                                 uint8 data, uint8 mask)
{
     return (BCM_E_UNAVAIL);
}


int bcm_esw_field_qualify_InnerIpFrag(int unit, bcm_field_entry_t entry,
                                  bcm_field_IpFrag_t frag_info)
{
     return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerTtl(int unit, bcm_field_entry_t entry,
                          uint8 data, uint8 mask)
{
     return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_IpAuth(int unit, bcm_field_entry_t entry,
                 uint8 data, uint8 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_BigIcmpCheck(int unit, bcm_field_entry_t entry,
                                         uint32 flag, uint32 size)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_IcmpTypeCode(int unit, bcm_field_entry_t entry,
                                         uint16 data,uint16 mask)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_IgmpTypeMaxRespTime(int unit, bcm_field_entry_t entry,
                                         uint16 data,uint16 mask)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_create(int unit,  
                                 bcm_field_data_qualifier_t *data_qualifier)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_multi_get(int unit, 
                                                                                int qual_size, 
                                                                                int *qual_array, int *qual_count)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_get(int unit, 
                                                                        int qual_id, 
                                                                        bcm_field_data_qualifier_t *qual)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_destroy(int unit, int qual_id)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_destroy_all(int unit)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qset_data_qualifier_add(int unit, bcm_field_qset_t *qset,  
                                      int qual_id)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qset_data_qualifier_get(int unit, bcm_field_qset_t *qset, int qual_max,
                                  int *qual_arr, int *qual_count) 
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_data(int unit, bcm_field_entry_t eid, int qual_id,
                           uint8 *data, uint8 *mask, uint16 length)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_ethertype_add(int unit, int qual_id,
                                 bcm_field_data_ethertype_t *etype)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_ethertype_delete(int unit, int qual_id,
                                 bcm_field_data_ethertype_t *etype)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_ip_protocol_add(int unit, int qual_id,
                                 bcm_field_data_ip_protocol_t *ip_protocol)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_ip_protocol_delete(int unit, int qual_id,
                                 bcm_field_data_ip_protocol_t *ip_protocol)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_packet_format_add(int unit,  int qual_id,
                                 bcm_field_data_packet_format_t *packet_format)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_data_qualifier_packet_format_delete(int unit, int qual_id,
                                 bcm_field_data_packet_format_t *packet_format)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_compress(int unit, bcm_field_group_t group)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_priority_set(int unit, bcm_field_group_t group,
                                 int priority)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_group_priority_get(int unit, bcm_field_group_t group,
                                 int *priority)
{
    return (BCM_E_UNAVAIL);
}
int 
bcm_esw_policer_init(int unit)
{
    return (BCM_E_UNAVAIL);
}
int 
bcm_esw_policer_get(int unit, bcm_policer_t policer_id, 
                    bcm_policer_config_t *pol_cfg)
{
    return (BCM_E_UNAVAIL);
}
int 
bcm_esw_policer_set(int unit, bcm_policer_t policer_id, 
                    bcm_policer_config_t *pol_cfg)
{
    return (BCM_E_UNAVAIL);
}
int 
bcm_esw_field_entry_policer_attach(int unit, bcm_field_entry_t entry_id, 
                                   int level, bcm_policer_t policer_id)
{
    return (BCM_E_UNAVAIL);
}
int 
bcm_esw_field_entry_policer_detach(int unit, bcm_field_entry_t entry_id, 
                                   int level)
{
    return (BCM_E_UNAVAIL);
}
int 
bcm_esw_field_entry_policer_detach_all(int unit, bcm_field_entry_t entry_id)
{
    return (BCM_E_UNAVAIL);
}
int 
bcm_esw_field_entry_policer_get(int unit, bcm_field_entry_t entry_id, 
                                int level, bcm_policer_t *policer_id)
{
    return (BCM_E_UNAVAIL);
}
int 
bcm_esw_policer_create(int unit, bcm_policer_config_t *pol_cfg, 
                       bcm_policer_t *policer_id)
{
    return BCM_E_UNAVAIL;
}

int 
bcm_esw_policer_destroy(int unit, bcm_policer_t policer_id)
{
    return BCM_E_UNAVAIL;
}

int 
bcm_esw_policer_destroy_all(int unit)
{
    return BCM_E_UNAVAIL;
}
int 
bcm_esw_policer_traverse(int unit, bcm_policer_traverse_cb cb, 
                         void *user_data)
{
    return BCM_E_UNAVAIL;
}

int 
bcm_esw_field_stat_create(int unit, bcm_field_group_t group, int nstat, 
                          bcm_field_stat_t *stat_arr, int *stat_id) 
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_stat_create_id(int unit, bcm_field_group_t group, int nstat, 
                          bcm_field_stat_t *stat_arr, int stat_id) 
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_stat_attach(int unit, bcm_field_group_t field_group, 
                          uint32 stat_counter_id, uint32 *stat_id)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_stat_detach(int unit, uint32 stat_id)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_stat_counter_get(int unit, uint32 stat_id, bcm_field_stat_t stat, 
                               uint32 num_entries, uint32 *counter_indexes, 
                               bcm_stat_value_t *counter_values)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_stat_counter_set(int unit, uint32 stat_id, bcm_field_stat_t stat, 
                               uint32 num_entries, uint32 *counter_indexes, 
                               bcm_stat_value_t *counter_values)
{
    return (BCM_E_UNAVAIL);
}
int bcm_esw_field_stat_id_get(int               unit,
                              bcm_field_group_t group,
                              bcm_field_stat_t  stat, 
                              uint32            *stat_counter_id)
{
   return BCM_E_UNAVAIL;
}

int 
bcm_esw_field_stat_destroy(int unit, int stat_id)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_stat_size(int unit, int stat_id, int *stat_size)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_stat_config_get(int unit, int stat_id, int nstat, 
                              bcm_field_stat_t *stat_arr)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_stat_get(int unit, int stat_id, bcm_field_stat_t stat, 
                       uint64 *value)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_stat_get32(int unit, int stat_id, 
                             bcm_field_stat_t stat, uint32 *value)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_stat_multi_get(int unit, int stat_id, int nstat, 
                                 bcm_field_stat_t *stat_arr, uint64 *value_arr)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_stat_multi_get32(int unit, int stat_id, int nstat, 
                                   bcm_field_stat_t *stat_arr, 
                                   uint32 *value_arr)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_entry_stat_attach(int unit, bcm_field_entry_t entry, 
                                    int stat_id)
{
    return (BCM_E_UNAVAIL);
}

int bcm_esw_field_entry_stat_detach(int unit, bcm_field_entry_t entry,
                                    int stat_id)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_entry_stat_get(int unit, bcm_field_entry_t entry, int *stat_id)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_stat_set(int unit, int stat_id, bcm_field_stat_t stat, 
                       uint64 value)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_stat_set32(int unit, int stat_id, bcm_field_stat_t stat, 
                         uint32 value)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_stat_all_set(int unit, int stat_id, uint64 value)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_stat_all_set32(int unit, int stat_id, uint32 value)
{
    return (BCM_E_UNAVAIL);
}

int
bcm_esw_field_qualify_InnerIpType(int unit, bcm_field_entry_t entry,
                             bcm_field_IpType_t type)
{
    return (BCM_E_UNAVAIL);
}

int 
bcm_esw_field_qualify_DstL3Egress(int unit, 
                                  bcm_field_entry_t entry, 
                                  bcm_if_t if_id)
{
    return BCM_E_UNAVAIL; 
}

int 
bcm_esw_field_qualify_DstMulticastGroup(int unit, 
                                 bcm_field_entry_t entry, 
                                 bcm_gport_t group)
{
    return BCM_E_UNAVAIL; 
}

int 
bcm_esw_field_qualify_DstMultipath(int               unit, 
                                   bcm_field_entry_t entry, 
                                   bcm_if_t          mpintf
                                   )
{
    return BCM_E_UNAVAIL; 
}

int 
bcm_esw_field_qualify_DstMultipath_get(int               unit, 
                                       bcm_field_entry_t entry, 
                                       bcm_if_t          *mpintf
                                       )
{
    return BCM_E_UNAVAIL; 
}

int 
bcm_esw_field_qualify_SrcMplsGport(int unit, 
                               bcm_field_entry_t entry, 
                               bcm_gport_t mpls_port_id)
{
    return BCM_E_UNAVAIL; 
}


int 
bcm_esw_field_qualify_DstMplsGport(int unit, 
                               bcm_field_entry_t entry, 
                               bcm_gport_t mpls_port_id)
{
    return BCM_E_UNAVAIL; 
}


int 
bcm_esw_field_qualify_SrcMimGport(int unit, 
                              bcm_field_entry_t entry, 
                              bcm_gport_t mim_port_id)
{
    return BCM_E_UNAVAIL; 
}


int 
bcm_esw_field_qualify_DstMimGport(int unit, 
                              bcm_field_entry_t entry, 
                              bcm_gport_t mim_port_id)
{
    return BCM_E_UNAVAIL; 
}


int 
bcm_esw_field_qualify_SrcWlanGport(int unit, 
                               bcm_field_entry_t entry, 
                               bcm_gport_t wlan_port_id)
{
    return BCM_E_UNAVAIL; 
}

int 
bcm_esw_field_qualify_DstWlanGport(int unit, 
                               bcm_field_entry_t entry, 
                               bcm_gport_t wlan_port_id)
{
    return BCM_E_UNAVAIL; 
}

int 
bcm_esw_field_qualify_Loopback(int unit, 
                               bcm_field_entry_t entry, 
                               uint8 data, 
                               uint8 mask)
{
    return BCM_E_UNAVAIL; 
}

int 
bcm_esw_field_qualify_LoopbackType(int unit, 
                                   bcm_field_entry_t entry, 
                                   bcm_field_LoopbackType_t loopback_type)
{
    return BCM_E_UNAVAIL; 
}

int 
bcm_esw_field_qualify_TunnelType(int unit, 
                                 bcm_field_entry_t entry, 
                                 bcm_field_TunnelType_t tunnel_type)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_LoopbackType_get
 * Purpose:
 *      Get loopback type field qualification from a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      loopback_type - (OUT) Loopback type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_LoopbackType_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_LoopbackType_t *loopback_type)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_TunnelType_get
 * Purpose:
 *      Get tunnel type field qualification from a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      tunnel_type - (OUT) Tunnel type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TunnelType_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_TunnelType_t *tunnel_type)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstL3Egress_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstL3Egress
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      if_id - (OUT) L3 forwarding object.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstL3Egress_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_if_t *if_id)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMulticastGroup_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstMulticastGroup
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      group - (OUT) Multicast group id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMulticastGroup_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t *group)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMplsGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcMplsGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      mpls_port_id - (OUT) Mpls port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMplsGport_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t *mpls_port_id)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMplsGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstMplsGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      mpls_port_id - (OUT) Mpls port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMplsGport_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t *mpls_port_id)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMimGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcMimGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      mim_port_id - (OUT) Mim port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMimGport_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t *mim_port_id)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMimGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstMimGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      mim_port_id - (OUT) Mim port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMimGport_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t *mim_port_id)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcWlanGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcWlanGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      wlan_port_id - (OUT) Wlan port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcWlanGport_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t *wlan_port_id)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstWlanGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstWlanGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      wlan_port_id - (OUT) Wlan port id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstWlanGport_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t *wlan_port_id)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Loopback_get
 * Purpose:
 *      Get loopback field qualification from  a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      data - (OUT) Data to qualify with.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Loopback_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_port_t *data, 
    bcm_port_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_OutPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOutPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OutPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_port_t *data, 
    bcm_port_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InPorts_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInPorts
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InPorts_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_pbmp_t *data, 
    bcm_pbmp_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_OutPorts_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOutPorts
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OutPorts_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_pbmp_t *data, 
    bcm_pbmp_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Drop_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDrop
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Drop_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcModid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModid_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_module_t *data, 
    bcm_module_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcPortTgid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcPortTgid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcPortTgid_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_port_t *data, 
    bcm_port_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data_modid - (OUT) Qualifier module id.
 *      mask_modid - (OUT) Qualifier module id mask.
 *      data_port - (OUT) Qualifier port id.
 *      mask_port - (OUT) Qualifier port id mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_module_t *data_modid, 
    bcm_module_t *mask_modid, 
    bcm_port_t *data_port, 
    bcm_port_t *mask_port)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcTrunk_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcTrunk
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcTrunk_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_trunk_t *data, 
    bcm_trunk_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstModid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstModid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstModid_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_module_t *data, 
    bcm_module_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstPortTgid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstPortTgid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstPortTgid_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_port_t *data, 
    bcm_port_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data_modid - (OUT) Qualifier module id.
 *      mask_modid - (OUT) Qualifier module id mask.
 *      data_port - (OUT) Qualifier port id.
 *      mask_port - (OUT) Qualifier port id mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_module_t *data_modid, 
    bcm_module_t *mask_modid, 
    bcm_port_t *data_port, 
    bcm_port_t *mask_port)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstTrunk_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstTrunk
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstTrunk_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_trunk_t *data, 
    bcm_trunk_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerL4SrcPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerL4SrcPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerL4SrcPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_l4_port_t *data, 
    bcm_l4_port_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerL4DstPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerL4DstPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerL4DstPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_l4_port_t *data, 
    bcm_l4_port_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L4SrcPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL4SrcPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L4SrcPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_l4_port_t *data, 
    bcm_l4_port_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L4DstPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL4DstPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L4DstPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_l4_port_t *data, 
    bcm_l4_port_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlan_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOuterVlan
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlan_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlan_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerVlan
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlan_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_EtherType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyEtherType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_EtherType_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *data, 
    uint16 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_EqualL4Port_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyEqualL4Port
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      flag - (OUT) Qualifier flags.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_EqualL4Port_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *flag)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpProtocol_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpProtocol
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpProtocol_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpInfo_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpInfo
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpInfo_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_PacketRes_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyPacketRes
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_PacketRes_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip_t *data, 
    bcm_ip_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip_t *data, 
    bcm_ip_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Tos_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTos
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Tos_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DSCP_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDSCP
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DSCP_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpFlags_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpFlags
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpFlags_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_TcpControl_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTcpControl
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TcpControl_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_TcpSequenceZero_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTcpSequenceZero
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      flag - (OUT) Qualifier match flags.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TcpSequenceZero_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *flag)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_TcpHeaderSize_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTcpHeaderSize
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TcpHeaderSize_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ttl_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTtl
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ttl_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_RangeCheck_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyRangeCheck
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      max_count - (IN) Max entries to fill.
 *      range - (OUT) Range checkers array.
 *      invert - (OUT) Range checkers invert array.
 *      count - (OUT) Number of filled range checkers.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_RangeCheck_get(
    int unit, 
    bcm_field_entry_t entry, 
    int max_count, 
    bcm_field_range_t *range, 
    int *invert, 
    int *count)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIp6_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIp6
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIp6_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstIp6_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstIp6
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstIp6_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIp6High_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIp6High
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIp6High_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIp6Low_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIp6Low
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIp6Low_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstIp6Low_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstIp6Low
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstIp6Low_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcIpEqualDstIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcIpEqualDstIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      flag - (OUT) Qualifier match flags.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcIpEqualDstIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *flag)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstIp6High_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstIp6High
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstIp6High_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ip6NextHeader_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIp6NextHeader
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ip6NextHeader_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ip6TrafficClass_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIp6TrafficClass
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ip6TrafficClass_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIp6FlowLabel_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIp6FlowLabel
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIp6FlowLabel_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ip6FlowLabel_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIp6FlowLabel
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ip6FlowLabel_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Ip6HopLimit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIp6HopLimit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Ip6HopLimit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMac_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcMac
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMac_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_mac_t *data, 
    bcm_mac_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstMac_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstMac
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstMac_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_mac_t *data, 
    bcm_mac_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_PacketFormat_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyPacketFormat
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_PacketFormat_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcMacGroup_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcMacGroup
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcMacGroup_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIpType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIpType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      type - (OUT) Inner ip header ip type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIpType_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpType_t *type)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_ForwardingType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyForwardingType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      type - (OUT) Qualifier match forwarding type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ForwardingType_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_ForwardingType_t *type)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      type - (OUT) Qualifier match ip type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpType_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpType_t *type)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2Format_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2Format
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      type - (OUT) Qualifier match l2 format.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2Format_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_L2Format_t *type)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_VlanFormat_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyVlanFormat
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_VlanFormat_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_MHOpcode_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyMHOpcode
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_MHOpcode_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_UserDefined_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyUserDefined
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      udf_id - (IN) Udf spec id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_UserDefined_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_udf_t udf_id, 
    uint8 data[BCM_FIELD_USER_FIELD_SIZE], 
    uint8 mask[BCM_FIELD_USER_FIELD_SIZE])
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_HiGig_get
 * Purpose:
 *      Qualify on HiGig packets.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_HiGig_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InterfaceClassPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInterfaceClassPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InterfaceClassPort_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InterfaceClassL2_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInterfaceClassL2
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InterfaceClassL2_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InterfaceClassL3_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInterfaceClassL3
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InterfaceClassL3_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcClassL2_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcClassL2
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcClassL2_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcClassL3_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcClassL3
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcClassL3_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcClassField_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcClassField
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcClassField_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstClassL2_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstClassL2
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstClassL2_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstClassL3_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstClassL3
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstClassL3_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstClassField_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstClassField
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstClassField_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3IntfGroup_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3IntfGroup
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3IntfGroup_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_if_group_t *data, 
    bcm_if_group_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpProtocolCommon_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpProtocolCommon
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      protocol - (OUT) Qualifier protocol encoding.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpProtocolCommon_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpProtocolCommon_t *protocol)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIpProtocolCommon_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIpProtocolCommon
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      protocol - (OUT) Qualifier inner ip protocol encodnig.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIpProtocolCommon_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpProtocolCommon_t *protocol)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Snap_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySnap
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Snap_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_snap_header_t *data, 
    bcm_field_snap_header_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Llc_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyLlc
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Llc_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_llc_header_t *data, 
    bcm_field_llc_header_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerTpid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerTpid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      tpid - (OUT) Qualifier tpid.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerTpid_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *tpid)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_OuterTpid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOuterTpid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      tpid - (OUT) Qualifier tpid.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterTpid_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *tpid)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_PortClass_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyPortClass
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_PortClass_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3Routable_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3Routable
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3Routable_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpFrag_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpFrag
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      frag_info - (OUT) Qualifier ip framentation encoding.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpFrag_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpFrag_t *frag_info)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_LookupClass0_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyLookupClass0
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_LookupClass0_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Vrf_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyVrf
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Vrf_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3Ingress_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyVrf
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3Ingress_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_ExtensionHeaderType_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyExtensionHeaderType
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ExtensionHeaderType_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_ExtensionHeaderSubCode_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyExtensionHeaderSubCode
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ExtensionHeaderSubCode_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_ExtensionHeader2Type_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyExtensionHeader2Type
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ExtensionHeader2Type_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L4Ports_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL4Ports
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L4Ports_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_MirrorCopy_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyMirrorCopy
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_MirrorCopy_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_TunnelTerminated_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTunnelTerminated
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TunnelTerminated_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_MplsTerminated_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyMplsTerminated
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_MplsTerminated_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerSrcIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerSrcIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerSrcIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip_t *data, 
    bcm_ip_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerDstIp_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDstIp
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerDstIp_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip_t *data, 
    bcm_ip_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerSrcIp6_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerSrcIp6
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerSrcIp6_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerDstIp6_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDstIp6
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerDstIp6_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerSrcIp6High_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerSrcIp6High
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerSrcIp6High_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerDstIp6High_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDstIp6High
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerDstIp6High_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_ip6_t *data, 
    bcm_ip6_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerTtl_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerTtl
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerTtl_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerTos_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDSCP
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerTos_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerDSCP_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerDSCP
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerDSCP_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIpProtocol_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIpProtocol
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIpProtocol_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerIpFrag_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInnerIpFrag
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      frag_info - (OUT) Inner ip header fragmentation info.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerIpFrag_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_IpFrag_t *frag_info)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DosAttack_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDosAttack
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DosAttack_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpmcStarGroupHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpmcStarGroupHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpmcStarGroupHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_MyStationHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyMyStationHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_MyStationHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2PayloadFirstEightBytes_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifyL2PayloadFirstEightBytes
 *          qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data1 - (OUT) Qualifier first four bytes of match data.
 *      data2 - (OUT) Qualifier last four bytes of match data.
 *      mask1 - (OUT) Qualifier first four bytes of match mask.
 *      mask2 - (OUT) Qualifier last four bytes of match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2PayloadFirstEightBytes_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data1, uint32 *data2,
    uint32 *mask1, uint32 *mask2)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3DestRouteHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3DestRouteHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3DestRouteHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3DestHostHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3DestHostHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3DestHostHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L3SrcHostHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL3SrcHostHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L3SrcHostHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2CacheHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2CacheHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2CacheHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2StationMove_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2StationMove
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2StationMove_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2DestHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2DestHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2DestHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2SrcStatic_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2SrcStatic
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2SrcStatic_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_L2SrcHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyL2SrcHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_L2SrcHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IngressStpState_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIngressStpState
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IngressStpState_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_ForwardingVlanValid_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyForwardingVlanValid
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ForwardingVlanValid_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcVirtualPortValid_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifySrcVirtualPortValid
 *      qualifier from the field entry.
 * Parameters:
 *      unit    - (IN) Unit number.
 *      entry   - (IN) BCM field entry id.
 *      data    - (OUT) Qualifier match data.
 *      mask    - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcVirtualPortValid_get(int unit,
                                              bcm_field_entry_t entry,
                                              uint8 *data,
                                              uint8 *mask)
{
    return (BCM_E_UNAVAIL);
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstL3EgressNextHops_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifyDstL3EgressNextHops
 *      qualifier from the field entry.
 * Parameters:
 *      unit    - (IN) Unit number.
 *      entry   - (IN) BCM field entry id.
 *      data    - (OUT) Qualifier match data.
 *      mask    - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstL3EgressNextHops_get(int unit,
    bcm_field_entry_t entry,
    uint32 *data,
    uint32 *mask)
{
    return (BCM_E_UNAVAIL);
}

/*
 * Function:
 *      bcm_esw_field_qualify_VlanTranslationHit_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyVlanTranslationHit
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_VlanTranslationHit_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IpAuth_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIpAuth
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IpAuth_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_BigIcmpCheck_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyBigIcmpCheck
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      flag - (OUT) Flag.
 *      size - (OUT) Size.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_BigIcmpCheck_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *flag, 
    uint32 *size)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IcmpTypeCode_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIcmpTypeCode
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IcmpTypeCode_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *data, 
    uint16 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IgmpTypeMaxRespTime_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIgmpTypeMaxRespTime
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IgmpTypeMaxRespTime_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint16 *data, 
    uint16 *mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_TranslatedVlanFormat
 * Purpose:
 *      Set match criteria for bcmFieildQualifyTranslatedVlanFormat
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TranslatedVlanFormat(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IntPriority
 * Purpose:
 *      Set match criteria for bcmFieildQualifyIntPriority
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IntPriority(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_Color
 * Purpose:
 *      Set match criteria for bcmFieildQualifyColor
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      color - (IN) Qualifier match color.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Color(int unit, bcm_field_entry_t entry, 
                            uint8 color)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_FibreChanOuter
 * Purpose:
 *      Add Fibre Channel outer header type field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      fibre_chan_type - (IN) Data to qualify with.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FibreChanOuter(int unit, 
                             bcm_field_entry_t entry, 
                             bcm_field_FibreChan_t fibre_chan_type)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_qualify_FibreChanInner
 * Purpose:
 *      Add Fibre Channel inner header type field qualification to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      fibre_chan_type - (IN) Data to qualify with.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FibreChanInner(int unit, 
                             bcm_field_entry_t entry, 
                             bcm_field_FibreChan_t fibre_chan_type)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_qualify_VnTag
 * Purpose:
 *      Add NIV VN tag field qualification to a field entry.
 * Parameters:
 *      unit  - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      data  - (IN) Qualifier match data.
 *      mask  - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_esw_field_qualify_VnTag(int unit, bcm_field_entry_t entry,
                            uint32 data, uint32 mask)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_qualify_CnTag
 * Purpose:
 *      Add QCN CN tag field qualification to a field entry.
 * Parameters:
 *      unit  - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      data  - (IN) Qualifier match data.
 *      mask  - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_esw_field_qualify_CnTag(int unit, bcm_field_entry_t entry,
                            uint32 data, uint32 mask)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_qualify_FabricQueueTag
 * Purpose:
 *      Add Fabric Queue tag field qualification to a field entry.
 * Parameters:
 *      unit  - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      data  - (IN) Qualifier match data.
 *      mask  - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_esw_field_qualify_FabricQueueTag(int unit, bcm_field_entry_t entry,
                                     uint32 data, uint32 mask)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModPortGport
 * Purpose:
 *      Set match criteria for bcmFieildQualifySrcModPortGport
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match gport.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModPortGport(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t data)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModuleGport
 * Purpose:
 *      Set match criteria for bcmFieildQualifySrcModuleGport
 *                     qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match gport.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModuleGport(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t data)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_TranslatedVlanFormat_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyTranslatedVlanFormat
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_TranslatedVlanFormat_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_IntPriority_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyIntPriority
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_IntPriority_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Color_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyColor
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      color - (OUT) Qualifier match color.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Color_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *color)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_FibreChannOuter_get
 * Purpose:
 *      Get Fibre Channel outer header type field qualification from a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      fibre_chan_type - (OUT) Fibre Channel header type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FibreChanOuter_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_FibreChan_t *fibre_chan_type)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_FibreChannInner_get
 * Purpose:
 *      Get Fibre Channel inner header type field qualification from a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry id.
 *      fibre_chan_type - (OUT) Fibre Channel header type.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FibreChanInner_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_FibreChan_t *fibre_chan_type)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_VnTag_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifyVnTag
 *      qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_VnTag_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_CnTag_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifyCnTag
 *      qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_CnTag_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_FabricQueueTag_get
 * Purpose:
 *      Get match criteria for bcmFieldQualifyFabricQueueTag
 *      qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FabricQueueTag_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint32 *data, 
    uint32 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModPortGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcModPortGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match gport.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModPortGport_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t *data)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_SrcModuleGport_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifySrcModuleGport
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match gport.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_SrcModuleGport_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_gport_t *data)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualifier_delete
 * Purpose:
 *      Remove match criteria from a field processor entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      qual_id - (IN) BCM field qualifier id.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualifier_delete(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_qualify_t qual_id)
{
    return BCM_E_UNAVAIL; 
}


/* Function: bcm_esw_field_group_wlan_create_mode
 *     
 * Purpose:
 *     Create a wlan field group with a mode (single, double, etc.).
 *
 * Parameters:
 *     unit - BCM device number.
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - (OUT) field Group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_wlan_create_mode(int unit, bcm_field_qset_t qset, int pri,
                                     bcm_field_group_mode_t mode,
                                     bcm_field_group_t *group)
{
    return BCM_E_UNAVAIL; 
}

/* Function: bcm_esw_field_group_wlan_create_mode_id
 *     
 * Purpose:
 *     Create a wlan field group with a mode (single, double, etc.).
 *
 * Parameters:
 *     unit - BCM device number.
 *     qset - Field qualifier set
 *     pri  - Priority within allowable range,
 *            or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a
 *            priority; each priority value may be used only once
 *    mode  - Group mode (single, double, triple or Auto-wide)
 *    group - (OUT) field Group ID
 *
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_wlan_create_mode_id(int unit, bcm_field_qset_t qset, int pri,
                                        bcm_field_group_mode_t mode,
                                        bcm_field_group_t group)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanId
 * Purpose:
 *       Set match criteria for bcmFieildQualifyOuterVlanId
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanId(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t data, 
    bcm_vlan_t mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanPri
 * Purpose:
 *       Set match criteria for bcmFieildQualifyOuterVlanPri
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanPri(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanCfi
 * Purpose:
 *       Set match criteria for bcmFieildQualifyOuterVlanCfi
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanCfi(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanId
 * Purpose:
 *       Set match criteria for bcmFieildQualifyInnerVlanId
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanId(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t data, 
    bcm_vlan_t mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanPri
 * Purpose:
 *       Set match criteria for bcmFieildQualifyInnerVlanPri
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanPri(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanCfi
 * Purpose:
 *       Set match criteria for bcmFieildQualifyInnerVlanCfi
 *                       qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanCfi(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanId_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyOuterVlanId
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanId_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanPri_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyOuterVlanPri
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanPri_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_OuterVlanCfi_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyOuterVlanCfi_get
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OuterVlanCfi_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanId_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyInnerVlanId
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanId_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanPri_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyInnerVlanPri
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanPri_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_InnerVlanCfi_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyInnerVlanCfi_get
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InnerVlanCfi_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstHiGig
 * Purpose:
 *      Qualify on HiGig destination packets.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstHiGig(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 data, 
    uint8 mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_DstHiGig_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyDstHiGig
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_DstHiGig_get(
    int unit, 
    bcm_field_entry_t entry, 
    uint8 *data, 
    uint8 *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_ForwardingVlanId_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyForwardingVlanId
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ForwardingVlanId_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t *data, 
    bcm_vlan_t *mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_Vpn_get
 * Purpose:
 *       Get match criteria for bcmFieildQualifyVpn
 *                       qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Vpn_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vpn_t *data, 
    bcm_vpn_t *mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_ForwardingVlanId
 * Purpose:
 *      Set match criteria for bcmFieildQualifyForwardingVlanId
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_ForwardingVlanId(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vlan_t data, 
    bcm_vlan_t mask)
{
    return BCM_E_UNAVAIL; 
}


/*
 * Function:
 *      bcm_esw_field_qualify_Vpn
 * Purpose:
 *      Set match criteria for bcmFieildQualifyVpn
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_Vpn(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_vpn_t data, 
    bcm_vpn_t mask)
{
    return BCM_E_UNAVAIL; 
}
/*
 * Function:
 *      bcm_esw_field_qualify_FlowId
 * Purpose:
 *      Set match criteria for bcmFieildQualifyFlowId
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */

int 
bcm_esw_field_qualify_FlowId(int unit, bcm_field_entry_t entry,
                 uint16 data, uint16 mask)
{
    return BCM_E_UNAVAIL; 
}
/*
 * Function:
 *      bcm_esw_field_qualify_InVPort
 * Purpose:
 *      Set match criteria for bcmFieildQualifyInVPort
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */

int 
bcm_esw_field_qualify_InVPort(int unit, bcm_field_entry_t entry,
                 uint8 data, uint8 mask)
{
    return BCM_E_UNAVAIL; 
}
/*
 * Function:
 *      bcm_esw_field_qualify_OutVPort
 * Purpose:
 *      Set match criteria for bcmFieildQualifyOutVPort
 *      qualifier in the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (IN) Qualifier match data.
 *      mask - (IN) Qualifier match data.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */

int 
bcm_esw_field_qualify_OutVPort(int unit, bcm_field_entry_t entry,
                 uint8 data, uint8 mask)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_qualify_FlowId_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyFlowId
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_FlowId_get(int unit, bcm_field_entry_t entry,
                 uint16 *data, uint16 *mask)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_qualify_InVPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyInVPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_InVPort_get(int unit, bcm_field_entry_t entry,
                 uint8 *data, uint8 *mask)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_qualify_OutVPort_get
 * Purpose:
 *      Get match criteria for bcmFieildQualifyOutVPort
 *                     qualifier from the field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) BCM field entry id.
 *      data - (OUT) Qualifier match data.
 *      mask - (OUT) Qualifier match mask.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_qualify_OutVPort_get(int unit, bcm_field_entry_t entry,
                 uint8 *data, uint8 *mask)
{
    return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_esw_field_action_mac_add
 * Purpose:
 *      Add an action to a field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry Id.
 *      action - (IN) Field action id.
 *      mac - (IN) Field action parameter.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_action_mac_add(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_action_t action, 
    bcm_mac_t mac)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_action_mac_get
 * Purpose:
 *      Retrieve the parameters for an action previously added to a
 *      field entry.
 * Parameters:
 *      unit - (IN) Unit number.
 *      entry - (IN) Field entry Id.
 *      action - (IN) Field action id.
 *      mac - (IN) Field action argument.
 * Returns:
 *      BCM_E_XXX
 * Notes:
 */
int 
bcm_esw_field_action_mac_get(
    int unit, 
    bcm_field_entry_t entry, 
    bcm_field_action_t action, 
    bcm_mac_t *mac)
{
    return BCM_E_UNAVAIL; 
}

/*
 * Function:
 *      bcm_esw_field_group_traverse
 * Purpose:
 *      Traverse all the fp groups in the system, calling a specified
 *      callback for each one
 * Parameters:
 *      unit - (IN) Unit number.
 *      callback - (IN) A pointer to the callback function to call for each fp group
 *      user_data - (IN) Pointer to user data to supply in the callback
 * Returns:
 *      BCM_E_xxx
 * Notes:
 */
int 
bcm_esw_field_group_traverse(int unit, bcm_field_group_traverse_cb callback,
                             void *user_data)
{
    return BCM_E_UNAVAIL; 
}

/* Function: bcm_esw_field_group_config_create
 *
 * Purpose:
 *     Create a group with a mode (single, double, etc.), a port bitmap,
 *     group size and a Group ID. 
 * Parameters:
 *     unit - BCM device number.
 *     group_config - Group create attributes namely:
 *          flags       - (IN) Bits indicate which parameters have been
 *                             passed to API and should be used during group
 *                             creation.
 *          qset        - (IN) Field qualifier set
 *          priority    - (IN) Priority within allowable range,
 *                             or BCM_FIELD_GROUP_PRIO_ANY to automatically
 *                             assign a priority; each priority value may be
 *                             used only once
 *          mode        - (IN) Group mode (single, double, triple or Auto-wide)
 *          ports       - (IN) Ports where group is defined
 *          group       - (IN/OUT) Requested Group ID. If Group ID is not set,
 *                              then API allocates and returns the created
 *                              Group ID.
 * Returns:
 *     BCM_E_INIT      - BCM unit not initialized
 *     BCM_E_RESOURCE  - no select codes will satisfy qualifier set
 *     BCM_E_NONE      - Success
 */
int
bcm_esw_field_group_config_create(int unit,
                                  bcm_field_group_config_t *group_config)
{
    return BCM_E_UNAVAIL; 
}
#endif  /* !BCM_FIELD_SUPPORT */
